main e56f13ec7fbf cached
125 files
2.2 MB
582.8k tokens
394 symbols
1 requests
Download .txt
Showing preview only (2,331K chars total). Download the full file or copy to clipboard to get everything.
Repository: wellflat/imageprocessing-labs
Branch: main
Commit: e56f13ec7fbf
Files: 125
Total size: 2.2 MB

Directory structure:
gitextract_72c15x7w/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── cv/
│   ├── corner_detection/
│   │   ├── README.md
│   │   └── cornerdetect.js
│   ├── fft/
│   │   ├── README.md
│   │   ├── fft.js
│   │   ├── filter.js
│   │   ├── qunit-fft-test.js
│   │   └── spectrum.js
│   ├── fisheye_transform/
│   │   ├── README.md
│   │   └── fisheye.js
│   ├── image_filter/
│   │   ├── README.md
│   │   ├── cavin.js
│   │   └── cvsandbox.js
│   ├── lsd/
│   │   ├── .babelrc
│   │   ├── .eslintignore
│   │   ├── .eslintrc.json
│   │   ├── README.md
│   │   ├── jsconfig.json
│   │   ├── line-segment-detector/
│   │   │   ├── .gitignore
│   │   │   ├── README.md
│   │   │   ├── jsconfig.json
│   │   │   ├── package.json
│   │   │   ├── src/
│   │   │   │   ├── funcs.ts
│   │   │   │   ├── lsd.ts
│   │   │   │   └── types.ts
│   │   │   ├── tsconfig.json
│   │   │   └── webpack.config.js
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app.js
│   │   │   ├── funcs.js
│   │   │   ├── index.html
│   │   │   ├── lsd.js
│   │   │   ├── lsd_component.js
│   │   │   └── types.js
│   │   └── webpack.config.js
│   ├── ort_web/
│   │   ├── HelloONNX.vue
│   │   └── README.md
│   ├── pixel_clustering/
│   │   ├── README.md
│   │   ├── kmeans.js
│   │   └── pixelcluster.js
│   ├── poisson_blending/
│   │   ├── README.md
│   │   └── poisson.js
│   ├── stereo_matching/
│   │   ├── README.md
│   │   ├── stereo-core.js
│   │   └── stereo.js
│   └── utils/
│       └── histogram.js
├── draw/
│   ├── README.md
│   ├── heart.js
│   ├── klein.js
│   ├── lib3d.js
│   ├── mobius.js
│   └── webgl/
│       ├── glsample.js
│       └── webglsample.html
└── ml/
    ├── README.md
    ├── arow/
    │   ├── README.md
    │   ├── app.ts
    │   ├── arow.ts
    │   ├── data_loader.ts
    │   ├── out/
    │   │   ├── app.js
    │   │   ├── arow.js
    │   │   ├── data_loader.js
    │   │   └── types.js
    │   └── types.ts
    ├── autoencoder/
    │   ├── css/
    │   │   └── app.css
    │   ├── index.html
    │   ├── out/
    │   │   ├── da.js
    │   │   ├── matrix.js
    │   │   └── vector.js
    │   ├── packages.config
    │   ├── spec/
    │   │   ├── Chutzpah.json
    │   │   ├── Tests/
    │   │   │   ├── da_test.ts
    │   │   │   ├── matrix_t_test.ts
    │   │   │   ├── matrix_test.ts
    │   │   │   ├── vector_t_test.ts
    │   │   │   └── vector_test.ts
    │   │   └── packages.config
    │   └── src/
    │       ├── app.ts
    │       ├── controller.ts
    │       ├── da.ts
    │       ├── matrix.ts
    │       ├── matrix_t.ts
    │       ├── storage.ts
    │       ├── vector.ts
    │       └── vector_t.ts
    ├── datasets/
    │   ├── README.md
    │   ├── boston_data.js
    │   ├── digits_data.ts
    │   ├── iris_data.ts
    │   └── out/
    │       ├── digits_data.js
    │       └── iris_data.js
    ├── decisiontree/
    │   └── decisiontree.js
    ├── gbdt/
    │   ├── README.md
    │   ├── package.json
    │   └── src/
    │       ├── boston_data.js
    │       ├── gradient_boosting.js
    │       ├── index.js
    │       ├── metrics.js
    │       └── regression_tree.js
    ├── kmeans/
    │   └── kmeans.js
    ├── logistic_regression/
    │   ├── logistic_regression.ts
    │   ├── matrix.ts
    │   └── vector.ts
    ├── scw/
    │   ├── README.md
    │   ├── data_loader.ts
    │   ├── out/
    │   │   ├── app.js
    │   │   ├── data_loader.js
    │   │   ├── scw.js
    │   │   └── types.js
    │   ├── scw.ts
    │   └── types.ts
    ├── t-sne/
    │   ├── .babelrc
    │   ├── .eslintrc.json
    │   ├── .gitignore
    │   ├── README.md
    │   ├── package.json
    │   └── src/
    │       ├── digits_data.js
    │       ├── index.js
    │       ├── tsne.js
    │       └── utils.js
    └── utils/
        ├── data_utils.ts
        ├── metrics.ts
        └── preprocessing.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
*.ts linguist-language=JavaScript


================================================
FILE: .gitignore
================================================
## macOS
.DS_Store

## emacs
*~
\#*
.\#*

## vim
*.swp
*.swo

## VSCode
.vscode/

## PROJECT::GENERAL
logs/
*.log
npm-debug.log*
node_modules/
typings/
.npm
.eslintcache

## PROJECT::SPECIFIC
dst/

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
obj/
*.dll
*.dll.config
*.pdb
*.suo

# Chutzpah Test files
_Chutzpah*


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2017 wellflat

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
## Image processing and Machine learning labs   [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)

computer vision, image processing and machine learning on the web browser or node

### note

* Fast Fourier Transform (1D/2D-FFT)
* Stereo Matching
* Poisson Image Editing
* Line Segment Detector
* Corner Detection
* Fish-Eye Transform
* Image Processing Filters
* Image Histogram Calculation
* Image Feature Extraction
* Decision Tree Learning
* K-Means++ Clustering
* Logistic Regression
* Adaptive Regularization of Weight Vectors (AROW)
* Soft Confidence Weighted Learning (SCW)
* Gradient Boosting Decision Tree (GBDT)
* Neural Network (Denoising Autoencoders)
* t-Distributed Stochastic Neighbor Embedding (t-SNE)
* 3D Shape Drawing (Mobius Strip, Klein Bottle, Heart Surface ...)
* WebGL Samples
* ONNX Runtime for Web (ORT Web)
* etc..

### demo
[Demo Site](https://rest-term.com/labs/html5/index.html) 

### license

Copyright © 2017 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php


================================================
FILE: cv/corner_detection/README.md
================================================
# Corner Detection Module

## description

Corner detection using Harris operator

see also [blog entry][entry]

### sample
[![corner_detection](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/room_corners.jpg)](http://rest-term.com/labs/html5/corner.html)

(Tests: IE9, Firefox15.0, Chrome21.0, Safari6.0, Opera12.0)

## usage

```js
// parameters for Harris corner detection
// blockSize: Neighborhood size (3×3 or 5×5)
// k: Harris detector free parameter (recommends 0.04 ~ 0.15)
// qualityLevel: Parameter characterizing the minimal accepted quality of image corners
var params = { blockSize: 3, k: 0.04, qualityLevel: 0.01 };
// img: ImageData object
// returns Array of detected corners
var corners = CornerDetector.detect(img, CornerDetector.HARRIS, params);

```

license
----------
Copyright © 2014 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/2986/


================================================
FILE: cv/corner_detection/cornerdetect.js
================================================
/**
 * Corner Detector module
 */
(function() {
  var CornerDetector;  // top-level namespace
  var _root = this;    // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    CornerDetector = exports;   // for CommonJS
  } else {
    CornerDetector = _root.CornerDetector = {};
  }

  var version = {
    release: '0.1.0',
    date: '2012-09'
  };
  CornerDetector.toString = function() {
    return "version " + version.release + ", released " + version.date;
  };

  // core operations
  var core = {
    detect : function(img, type, params) {
      core._validateParams(params);
      switch(type) {
      case 'eigen':
        // implement ?
        throw new Error('not implementation error');
        break;
      case 'harris':
        return core._detectHarris(img, params);
        break;
      case 'fast':
        // implement ?
        throw new Error('not implementation error');
        break;
      default:
        return core._detectHarris(img, params);
        break;
      }
    },
    _validateParams : function(params) {
      var _params = ['qualityLevel', 'blockSize', 'k'], msg = '';
      for(var i=0; i<_params.length; i++) {
        if(!params.hasOwnProperty(_params[i])) {
          msg = 'invalid parameters, required \'' + _params[i] + '\'';
          throw new Error(msg);
        }
        if(!parseFloat(params[_params[i]])) {
          msg = 'invalid parameters, required number \'' + _params[i] + '\'';
          throw new TypeError(msg);
        }
      }
      if(params.blockSize%2 !== 1) {
        throw new Error('odd number required \'blockSize\'');
      }
      if(params.blockSize > 5) {
        throw new Error('unsupported \'blockSize\' ' + params.blockSize);
      }
    },
    /* Harris Operator */
    _detectHarris : function(img, params) {
      var w = img.width,
          h = img.height,
          imgdata = img.data,
          len = w*h << 2,
          src, cov, eig, corners,
          r = (params.blockSize - 1)/2,
          dx, dy, dxdata, dydata, kernelx, kernely, maxval, quality,
          x, y, kx, ky, i, j, step, tmp;

      if(typeof Float32Array === 'function') {
        src = cov = new Float32Array(w*h*3);
        corners = new Float32Array(w*h);
      } else {
        src = cov = corners = [];
      }
      // change container, uint8 to float32
      for(i=0,j=0; i<len; i+=3,j+=4) {
        src[i] = imgdata[j];
        src[i + 1] = imgdata[j + 1];
        src[i + 2] = imgdata[j + 2];
      }
      // apply sobel filter
      switch(params.blockSize) {
      case 3:
        kernelx = [-1, 0, 1, -2, 0, 2, -1, 0, 1]; // 3*3 kernel
        kernely = [-1, -2, -1, 0, 0, 0, 1, 2, 1];
        break;
      case 5:
        kernelx = [1,  2, 0,  -2,  -1,  // 5*5 kernel
                   4,  8, 0,  -8,  -4,
                   6, 12, 0, -12,  -6,
                   4,  8, 0,  -8,  -4,
                   1,  2, 0,  -2,  -1];
        kernely = [-1, -4,  -6, -4, -1,
                   -2, -8, -12, -8, -2,
                    0,  0,   0,  0,  0,
                    2,  8,  12,  8,  2,
                    1,  4,   6,  4,  1];
        break;
      }
      dx = core._convolution(src, w, h, kernelx, 1);
      dy = core._convolution(src, w, h, kernely, 1);
      // store squared differences directly
      for(y=0; y<h; y++) {
        step = y*w;
        for(x=0; x<w; x++) {
          i = (step + x)*3;
          dxdata = dx[i];
          dydata = dy[i];
          cov[i] = dxdata*dxdata;      // dxx
          cov[i + 1] = dxdata*dydata;  // dxy
          cov[i + 2] = dydata*dydata;  // dyy
        }
      }
      // apply box blur filter
      cov = core._blur(cov, w, h, (params.blockSize - 1)/2);
      // compute Harris operator
      eig = core._calcHarris(cov, w, h, params.k);
      // suppress non-maxima values
      for(y=r; y<h-r; y++) {
        step = y*w;
        for(x=r; x<w-r; x++) {
          i = step + x;
          tmp = eig[i];
          for(ky=-r; (tmp!==0) && (ky<=r); ky++) {
            for(kx=-r; kx<=r; kx++) {
              if(eig[i + ky*w + kx] > tmp) {
                tmp = 0;
                break;
              }
            }
          }
          if(tmp !== 0) {
            corners[i] = eig[i];
          }
        }
      }
      // threshold
      maxval = 0;
      len = eig.length;
      for(i=0; i<len; i++) {
        if(corners[i] > maxval) maxval = corners[i];
      }
      quality = maxval*params.qualityLevel;
      for(j=0; j<len; j++) {
        if(corners[j] <= quality) {
          corners[j] = 0;
        }
      }
      return corners;
    },
    _calcHarris : function(data, width, height, k) {
      var w = width,
          h = height,
          cov = data,
          M, A, B, C, step, i;

      if(typeof Float32Array === 'function') {
        M = new Float32Array(w*h*3);
      } else {
        M = [];
      }
      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          i = (step + x)*3;
          A = cov[i];
          B = cov[i + 1];
          C = cov[i + 2];
          M[step + x] = (A*C - B*B - k*(A + C)*(A + C));
        }
      }
      return M;
    },
    /* convolution filter (as sobel/box filter, sigle channel) */
    _convolution : function(data, width, height, kernel, divisor) {
      var w = width,
          h = height,
          src = data,
          dst,
          div = 1/divisor,
          r = Math.sqrt(kernel.length),
          buff = [],
          i, j, k, v, px, py, step, kstep;

      if(divisor === 0) {
        throw new Error('division zero');
      }
      if(r%2 !== 1) {
        throw new Error('square kernel required');
      }
      if(typeof Float32Array === 'function') {
        dst = new Float32Array(w*h*3);
      } else {
        dst = [];
      }
      r = (r - 1)/2;
      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          buff[0] = buff[1] = buff[2] = 0;
          i = (step + x)*3;
          k = 0;
          // convolution
          for(var ky=-r; ky<=r; ky++) {
            py = y + ky;
            if(py <= 0 || h <= py) py = y;
            kstep = py*w;
            for(var kx=-r; kx<=r; kx++) {
              px = x + kx;
              if(px <= 0 || w <= px) px = x;
              j = (kstep + px)*3;
              buff[0] += src[j]*kernel[k];
              buff[1] += src[j + 1]*kernel[k];
              buff[2] += src[j + 2]*kernel[k];
              k++;
            }
          }
          dst[i] = buff[0]*div;
          dst[i + 1] = buff[1]*div;
          dst[i + 2] = buff[2]*div;
        }
      }
      return dst;
    },
    /* box blur filter */
    _blur : function(data, width, height, radius) {
      var kernel = [],
          size = (2*radius + 1)*(2*radius + 1);
      for(var i=0; i<size; i++) {
        kernel[i] = 1.0;
      }
      return core._convolution(data, width, height, kernel, 1);
    }
  };
  // aliases (public APIs and constants)
  CornerDetector.EIGEN = 'eigen';
  CornerDetector.HARRIS = 'harris';
  CornerDetector.FAST = 'fast';
  CornerDetector.detect = core.detect;
}).call(this);


================================================
FILE: cv/fft/README.md
================================================
# Fast Fourier Transform (FFT) Module

## description

1D-FFT/IFFT, 2D-FFT/IFFT, Frequency Filtering

see also [blog entry][entry]

### sample
[![2d_fft](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/fft_filter.jpg)](http://rest-term.com/labs/html5/fft.html)

(Tests: IE9, Firefox8.0, Chrome16.0, Safari5.0, Opera11.60)

## usage
### 1D-FFT/IFFT

```js
var x1 = [], y1 = [], x2 = [], y2 = [], x3 = [], y3 = [], N = 32;
for(var i=0; i<N; i++) {
  x1[i] = x2[i] = 6*Math.cos(6*Math.PI*i/N) + 4*Math.sin(18*Math.PI*i/N);
  y1[i] = y2[i] = 0.0;
}
// initialize
FFT.init(N);
// 1D-FFT
FFT.fft1d(x2, y2);
for(var j=0; j<N; j++) {
  x3[j] = x2[j];
  y3[j] = y2[j];
}
// 1D-IFFT
FFT.ifft1d(x3, y3);
var out = "";
for(var i=0; i<N; i++){
  out += i + ": (" + x1[i] + ", " +y1[i]+ ") (" +
    x2[i] + ", " + y2[i] + ") (" + x3[i] + ", " + y3[i] + ")\n";
}
console.log("N: (Source) (FFT) (IFFT)");
console.log(out);
```

### 2D-FFT/IFFT, Frequency Filtering (High-Pass/Low-Pass/Band-Pass)

```js
// for HTML5 Canvas
var spectrum = document.querySelector('#Spectrum').getContext('2d'),
    result = document.querySelector('#Result').getContext('2d'),
    image = new Image();
image.src = '/path/to/image';
image.addEventListener('load', function(e) {
  var w = image.width,
      h = image.height, // w == h
      re = [],
      im = [];

  // initialize, radix-2 required
  FFT.init(w);
  FrequencyFilter.init(w);
  SpectrumViewer.init(spectrum);
  spectrum.drawImage(image, 0, 0);
  var src = spectrum.getImageData(0, 0, w, h),
      data = src.data,
      radius = 30,
      i, val, p;
  for(var y=0; y<h; y++) {
    i = y*w;
    for(var x=0; x<w; x++) {
      re[i + x] = data[(i << 2) + (x << 2)];
      im[i + x] = 0.0;
    }
  }
  // 2D-FFT
  FFT.fft2d(re, im);
  // swap quadrant
  FrequencyFilter.swap(re, im);
  // High Pass Filter
  FrequencyFilter.HPF(re, im, radius);
  // Low Pass Filter
  FrequencyFilter.LPF(re, im, radius);
  // Band Path Filter
  FrequencyFilter.BPF(re, im, radius, radius/2);
  // render spectrum
  SpectrumViewer.render(re, im);
  // swap quadrant
  FrequencyFilter.swap(re, im);
  // 2D-IFFT
  FFT.ifft2d(re, im);
  for(var y=0; y<h; y++) {
    i = y*w;
    for(var x=0; x<w; x++) {
      val = re[i + x];
      p = (i << 2) + (x << 2);
      data[p] = data[p + 1] = data[p + 2] = val;
    }
  }
  // put result image on the canvas
  result.putImageData(src, 0, 0);
}, false);
```

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/2966/


================================================
FILE: cv/fft/fft.js
================================================
/**
 * Fast Fourier Transform module
 * 1D-FFT/IFFT, 2D-FFT/IFFT (radix-2)
 */
(function() {
  var FFT;           // top-level namespace
  var _root = this;  // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    FFT = exports;   // for CommonJS
  } else {
    FFT = _root.FFT = {};
  }

  var version = {
    release: '0.3.0',
    date: '2013-03'
  };
  FFT.toString = function() {
    return "version " + version.release + ", released " + version.date;
  };

  // core operations
  var _n = 0,          // order
      _bitrev = null,  // bit reversal table
      _cstb = null;    // sin/cos table
  var core = {
    init : function(n) {
      if(n !== 0 && (n & (n - 1)) === 0) {
        _n = n;
        core._initArray();
        core._makeBitReversalTable();
        core._makeCosSinTable();
      } else {
        throw new Error("init: radix-2 required");
      }
    },
    // 1D-FFT
    fft1d : function(re, im) {
      core.fft(re, im, 1);
    },
    // 1D-IFFT
    ifft1d : function(re, im) {
      var n = 1/_n;
      core.fft(re, im, -1);
      for(var i=0; i<_n; i++) {
        re[i] *= n;
        im[i] *= n;
      }
    },
    // 2D-FFT
    fft2d : function(re, im) {
      var tre = [],
          tim = [],
          i = 0;
      // x-axis
      for(var y=0; y<_n; y++) {
        i = y*_n;
        for(var x1=0; x1<_n; x1++) {
          tre[x1] = re[x1 + i];
          tim[x1] = im[x1 + i];
        }
        core.fft1d(tre, tim);
        for(var x2=0; x2<_n; x2++) {
          re[x2 + i] = tre[x2];
          im[x2 + i] = tim[x2];
        }
      }
      // y-axis
      for(var x=0; x<_n; x++) {
        for(var y1=0; y1<_n; y1++) {
          i = x + y1*_n;
          tre[y1] = re[i];
          tim[y1] = im[i];
        }
        core.fft1d(tre, tim);
        for(var y2=0; y2<_n; y2++) {
          i = x + y2*_n;
          re[i] = tre[y2];
          im[i] = tim[y2];
        }
      }
    },
    // 2D-IFFT
    ifft2d : function(re, im) {
      var tre = [],
          tim = [],
          i = 0;
      // x-axis
      for(var y=0; y<_n; y++) {
        i = y*_n;
        for(var x1=0; x1<_n; x1++) {
          tre[x1] = re[x1 + i];
          tim[x1] = im[x1 + i];
        }
        core.ifft1d(tre, tim);
        for(var x2=0; x2<_n; x2++) {
          re[x2 + i] = tre[x2];
          im[x2 + i] = tim[x2];
        }
      }
      // y-axis
      for(var x=0; x<_n; x++) {
        for(var y1=0; y1<_n; y1++) {
          i = x + y1*_n;
          tre[y1] = re[i];
          tim[y1] = im[i];
        }
        core.ifft1d(tre, tim);
        for(var y2=0; y2<_n; y2++) {
          i = x + y2*_n;
          re[i] = tre[y2];
          im[i] = tim[y2];
        }
      }
    },
    // core operation of FFT
    fft : function(re, im, inv) {
      var d, h, ik, m, tmp, wr, wi, xr, xi,
          n4 = _n >> 2;
      // bit reversal
      for(var l=0; l<_n; l++) {
        m = _bitrev[l];
        if(l < m) {
          tmp = re[l];
          re[l] = re[m];
          re[m] = tmp;
          tmp = im[l];
          im[l] = im[m];
          im[m] = tmp;
        }
      }
      // butterfly operation
      for(var k=1; k<_n; k<<=1) {
        h = 0;
        d = _n/(k << 1);
        for(var j=0; j<k; j++) {
          wr = _cstb[h + n4];
          wi = inv*_cstb[h];
          for(var i=j; i<_n; i+=(k<<1)) {
            ik = i + k;
            xr = wr*re[ik] + wi*im[ik];
            xi = wr*im[ik] - wi*re[ik];
            re[ik] = re[i] - xr;
            re[i] += xr;
            im[ik] = im[i] - xi;
            im[i] += xi;
          }
          h += d;
        }
      }
    },
    // initialize the array (supports TypedArray)
    _initArray : function() {
      if(typeof Uint8Array !== 'undefined') {
				if(_n<=256)
					_bitrev = new Uint8Array(_n);
				else if(_n<=65536)
					_bitrev = new Uint16Array(_n);
				else
					_bitrev = new Uint32Array(_n);
      } else {
        _bitrev = [];
      }
      if(typeof Float64Array !== 'undefined') {
        _cstb = new Float64Array(_n*1.25);
      } else {
        _cstb = [];
      }
    },
    // zero padding
    _paddingZero : function() {
      // TODO
    },
    // makes bit reversal table
    _makeBitReversalTable : function() {
      var i = 0,
          j = 0,
          k = 0;
      _bitrev[0] = 0;
      while(++i < _n) {
        k = _n >> 1;
        while(k <= j) {
          j -= k;
          k >>= 1;
        }
        j += k;
        _bitrev[i] = j;
      }
    },
    // makes trigonometiric function table
    _makeCosSinTable : function() {
      var n2 = _n >> 1,
          n4 = _n >> 2,
          n8 = _n >> 3,
          n2p4 = n2 + n4,
          t = Math.sin(Math.PI/_n),
          dc = 2*t*t,
          ds = Math.sqrt(dc*(2 - dc)),
          c = _cstb[n4] = 1,
          s = _cstb[0] = 0;
      t = 2*dc;
      for(var i=1; i<n8; i++) {
        c -= dc;
        dc += t*c;
        s += ds;
        ds -= t*s;
        _cstb[i] = s;
        _cstb[n4 - i] = c;
      }
      if(n8 !== 0) {
        _cstb[n8] = Math.sqrt(0.5);
      }
      for(var j=0; j<n4; j++) {
        _cstb[n2 - j]  = _cstb[j];
      }
      for(var k=0; k<n2p4; k++) {
        _cstb[k + n2] = -_cstb[k];
      }
    }
  };
  // aliases (public APIs)
  var apis = ['init', 'fft1d', 'ifft1d', 'fft2d', 'ifft2d'];
  for(var i=0; i<apis.length; i++) {
    FFT[apis[i]] = core[apis[i]];
  }
  FFT.fft = core.fft1d;
  FFT.ifft = core.ifft1d;
}).call(this);

/**
 * Spatial Frequency Filtering
 * High-pass/Low-pass/Band-pass Filter
 * Windowing using hamming window
 */
(function() {
  var FrequencyFilter;  // top-level namespace
  var _root = this;     // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    FrequencyFilter = exports;   // for CommonJS
  } else {
    FrequencyFilter = _root.FrequencyFilter = {};
  }

  // core operations
  var _n = 0;
  var core = {
    init : function(n) {
      if(n !== 0 && (n & (n - 1)) === 0) {
        _n = n;
      } else {
        throw new Error("init: radix-2 required");
      }
    },
    // swaps quadrant
    swap : function(re, im) {
      var xn, yn, i, j, k, l, tmp,
          len = _n >> 1;
      for(var y=0; y<len; y++) {
        yn = y + len;
        for(var x=0; x<len; x++) {
          xn = x + len;
          i = x + y*_n;
          j = xn + yn*_n;
          k = x + yn*_n;
          l = xn + y*_n;
          tmp = re[i];
          re[i] = re[j];
          re[j] = tmp;
          tmp = re[k];
          re[k] = re[l];
          re[l] = tmp;
          tmp = im[i];
          im[i] = im[j];
          im[j] = tmp;
          tmp = im[k];
          im[k] = im[l];
          im[l] = tmp;
        }
      }
    },
    // applies High-Pass Filter
    HPF : function(re, im, radius) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1,
          sqrt = Math.sqrt;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = sqrt(x*x + y*y);
          p = x + i;
          if(r < radius) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // applies Low-Pass Filter
    LPF : function(re, im, radius) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1,
          sqrt = Math.sqrt;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = sqrt(x*x + y*y);
          p = x + i;
          if(r > radius) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // applies Band-Pass Filter
    BPF : function(re, im, radius, bandwidth) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1,
          sqrt = Math.sqrt;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = sqrt(x*x + y*y);
          p = x + i;
          if(r < radius || r > (radius + bandwidth)) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // windowing using hamming window
    windowing : function(data, inv) {
      var len = data.length,
          pi = Math.PI,
          cos = Math.cos;
      for(var i=0; i<len; i++) {
        if(inv === 1) {
          data[i] *= 0.54 - 0.46*cos(2*pi*i/(len - 1));
        } else {
          data[i] /= 0.54 - 0.46*cos(2*pi*i/(len - 1));
        }
      }
    }
  };
  // aliases (public APIs)
  var apis = ['init', 'swap', 'HPF', 'LPF', 'BPF', 'windowing'];
  for(var i=0; i<apis.length; i++) {
    FrequencyFilter[apis[i]] = core[apis[i]];
  }
}).call(this);

/**
 * FFT Power Spectrum Viewer
 */
(function() {
  var SpectrumViewer;  // top-level namespace
  var _root = this;    // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    SpectrumViewer = exports;   // for CommonJS
  } else {
    SpectrumViewer = _root.SpectrumViewer = {};
  }

  // core operations
  var _context = null,
      _n = 0,
      _img = null,
      _data = null;
  var core = {
    init : function(context) {
      _context = context;
      _n = context.canvas.width,
      _img = context.getImageData(0, 0, _n, _n);
      _data = _img.data;
    },
    // renders FFT power spectrum on the canvas
    render : function(re, im, islog) {
      var val = 0,
          i = 0,
          p = 0,
          spectrum = [],
          max = 1.0,
          imax = 0.0,
          n2 = _n*_n,
          log = Math.log,
          sqrt = Math.sqrt;
      for(var i=0; i<n2; i++) {
        if(islog){
          spectrum[i] = log(Math.sqrt(re[i]*re[i] + im[i]*im[i]));
        } else {
          spectrum[i] = sqrt(re[i]*re[i] + im[i]*im[i]);
        }
        if(spectrum[i] > max) {
          max = spectrum[i];
        }
      }
      imax = 1/max;
      for(var j=0; j<n2; j++) {
        spectrum[j] = spectrum[j]*255*imax;
      }
      for(var y=0; y<_n; y++) {
        i = y*_n;
        for(var x=0; x<_n; x++) {
          val = spectrum[i + x];
          p = (i << 2) + (x << 2);
          _data[p] = 0;
          _data[p + 1] = val;
          _data[p + 2] = val >> 1;
        }
      }
      _context.putImageData(_img, 0, 0);
    }
  };
  // aliases (public APIs)
  SpectrumViewer.init = core.init;
  SpectrumViewer.render = core.render;
}).call(this);


================================================
FILE: cv/fft/filter.js
================================================
/**
 * Spatial Frequency Filtering
 * High-pass/Low-pass/Band-pass Filter
 * Windowing using hamming window
 */
(function() {
  var FrequencyFilter;  // top-level namespace
  var _root = this;     // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    FrequencyFilter = exports;   // for CommonJS
  } else {
    FrequencyFilter = _root.FrequencyFilter = {};
  }

  // core operations
  var _n = 0;
  var core = {
    init : function(n) {
      if(n !== 0 && (n & (n - 1)) === 0) {
        _n = n;
      } else {
        throw new Error("init: radix-2 required");
      }
    },
    // swap quadrant
    swap : function(re, im) {
      var xn, yn, i, j, k, l, tmp,
          len = _n >> 1;
      for(var y=0; y<len; y++) {
        yn = y + len;
        for(var x=0; x<len; x++) {
          xn = x + len;
          i = x + y*_n;
          j = xn + yn*_n;
          k = x + yn*_n;
          l = xn + y*_n;
          tmp = re[i];
          re[i] = re[j];
          re[j] = tmp;
          tmp = re[k];
          re[k] = re[l];
          re[l] = tmp;
          tmp = im[i];
          im[i] = im[j];
          im[j] = tmp;
          tmp = im[k];
          im[k] = im[l];
          im[l] = tmp;
        }
      }
    },
    // apply High-Pass Filter
    HPF : function(re, im, radius) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = Math.sqrt(x*x + y*y);
          p = x + i;
          if(r < radius) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // apply Low-Pass Filter
    LPF : function(re, im, radius) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = Math.sqrt(x*x + y*y);
          p = x + i;
          if(r > radius) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // apply Band-Pass Filter
    BPF : function(re, im, radius, bandwidth) {
      var i = 0,
          p = 0,
          r = 0.0,
          n2 = _n >> 1;
      for(var y=-n2; y<n2; y++) {
        i = n2 + (y + n2)*_n;
        for(var x=-n2; x<n2; x++) {
          r = Math.sqrt(x*x + y*y);
          p = x + i;
          if(r < radius || r > (radius + bandwidth)) {
            re[p] = im[p] = 0;
          }
        }
      }
    },
    // windowing using hamming window
    windowing : function(data, inv) {
      var len = data.length,
          pi = Math.PI;
      for(var i=0; i<len; i++) {
        if(inv === 1) {
          data[i] *= 0.54 - 0.46*Math.cos(2*pi*i/(len - 1));
        } else {
          data[i] /= 0.54 - 0.46*Math.cos(2*pi*i/(len - 1));
        }
      }
    }
  };
  // aliases (public APIs)
  var apis = ['init', 'swap', 'HPF', 'LPF', 'BPF', 'windowing'];
  for(var i=0; i<apis.length; i++) {
    FrequencyFilter[apis[i]] = core[apis[i]];
  }
}).call(this);


================================================
FILE: cv/fft/qunit-fft-test.js
================================================
module("1D/2D-FFT/IFFT");
asyncTest("FFT module tests", function() {
  try {
    var image = new Image(),
        canvas = document.querySelector('#qunit-canvas'),
        context = canvas.getContext('2d');
    image.src = './lena_gray.jpg';
    image.addEventListener('load', function(e) {
      start();
      context.drawImage(image, 0, 0);
      var w = image.width,
          h = image.height,
          re = [],
          im = [],
          src = context.getImageData(0, 0, w, h),
          data = src.data;
      raises(function() {
        FFT.init(3);
      }, "raises Error, required radix-2");
      FFT.init(w);
      for(var y=0; y<h; y++) {
        var i = y*w;
        for(var x=0; x<w; x++) {
          re[i + x] = data[(i << 2) + (x << 2)];
          im[i + x] = 0.0;
        }
      }
      var re2 = re.concat(),
          im2 = im.concat(),
          sample = 100,
          diff = 0.0,
          error = 1.0e-12;
      // 1D-FFT/IFFT
      FFT.fft1d(re, im);
      FFT.ifft1d(re, im);
      for(var j=0; j<sample*sample; j+=sample) {
        diff = re[j] - re2[j];
        diff = diff > 0 ? diff : -diff;
        ok(diff < error, "fft1d -> ifft1d, Re error: " + diff);
        diff = im[j] - im2[j];
        diff = diff > 0 ? diff : -diff;
        ok(diff < error, "fft1d -> ifft1d, Im error: " + diff);
      }
      // 2D-FFT/IFFT
      re = re2.concat();
      im = im2.concat();
      FFT.fft2d(re, im);
      FFT.ifft2d(re, im);
      for(var j=0; j<sample*sample; j+=sample) {
        diff = re[j] - re2[j];
        diff = diff > 0 ? diff : -diff;
        ok(diff < error, "fft2d -> ifft2d, Re error: " + diff);
        diff = im[j] - im2[j];
        diff = diff > 0 ? diff : -diff;
        ok(diff < error, "fft2d -> ifft2d, Im error: " + diff);
      }
    }, false);
  } catch(e) {
    return;
  }
});

================================================
FILE: cv/fft/spectrum.js
================================================
/**
 * FFT Power Spectrum Viewer
 */
(function() {
  var SpectrumViewer;  // top-level namespace
  var _root = this;    // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    SpectrumViewer = exports;   // for CommonJS
  } else {
    SpectrumViewer = _root.SpectrumViewer = {};
  }

  // core operations
  var _context = null,
      _n = 0,
      _img = null,
      _data = null;
  var core = {
    init : function(context) {
      _context = context;
      _n = context.canvas.width,
      _img = context.getImageData(0, 0, _n, _n);
      _data = _img.data;
    },
    // render FFT power spectrum on the Canvas
    render : function(re, im, islog) {
      var val = 0,
          i = 0,
          p = 0,
          spectrum = [],
          max = 1.0,
          imax = 0.0,
          n2 = _n*_n;
      for(var i=0; i<n2; i++) {
        if(islog){
          spectrum[i] = Math.log(Math.sqrt(re[i]*re[i] + im[i]*im[i]));
        } else {
          spectrum[i] = Math.sqrt(re[i]*re[i] + im[i]*im[i]);
        }
        if(spectrum[i] > max) {
          max = spectrum[i];
        }
      }
      imax = 1/max;
      for(var j=0; j<n2; j++) {
        spectrum[j] = spectrum[j]*255*imax;
      }
      for(var y=0; y<_n; y++) {
        i = y*_n;
        for(var x=0; x<_n; x++) {
          val = spectrum[i + x];
          p = (i << 2) + (x << 2);
          _data[p] = 0;
          _data[p + 1] = val;
          _data[p + 2] = val >> 1;
        }
      }
      _context.putImageData(_img, 0, 0);
    }
  };
  // aliases (public APIs)
  SpectrumViewer.init = core.init;
  SpectrumViewer.render = core.render;
}).call(this);


================================================
FILE: cv/fisheye_transform/README.md
================================================
# Fish-Eye Transform Module

## description

Circular Fish-Eye transform

see also [blog entry][entry]

### sample
[![fisheye_transform](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/fisheye_transform.jpg)](http://rest-term.com/labs/html5/fisheye.html)

(Tests: IE9, Firefox16.0, Chrome21.0, Safari6.0, Opera12.0)

## usage

```js
//  img: ImageData object
//  focalLength: focal-length Number (int)
//  radius: circle radius Number (int)
var focalLength = 55;
var radius = 60;

// returns ImageData object
var result = Fisheye.transform(img, focalLength, radius);

```

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[FishEye]: http://rest-term.com/labs/html5/fisheye.html
[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/2991/


================================================
FILE: cv/fisheye_transform/fisheye.js
================================================
/**
 * Fish-Eye Transform module
 */
(function() {
  var Fisheye;        // top-level namespace
  var _root = this;   // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    Fisheye = exports;   // for CommonJS
  } else {
    Fisheye = _root.Fisheye = {};
  }

  var version = {
    release: '0.1.0',
    date: '2012-09'
  };
  Fisheye.toString = function() {
    return "version " + version.release + ", released " + version.date;
  };

  // core operations
  var _ctx = document.createElement('canvas').getContext('2d');
  var core = {
    transform : function(img, focalLength, radius) {
      var w = img.width,
          h = img.height,
          src = img.data,
          f = focalLength,
          r = radius,
          buff = [0, 0, 0],
          dstimg, dst,
          sqrt = Math.sqrt,
          round = Math.round,
          cx, cy, dx, dy, nx, ny, d, fd, i, j, step;

      _ctx.canvas.width = w;
      _ctx.canvas.height = h;
      _ctx.fillStyle = 'rgba(0, 0, 0, 0)';
      _ctx.fillRect(0, 0, w, h);
      dstimg = _ctx.getImageData(0, 0, w, h);
      dst = dstimg.data;
      cx = w/2;
      cy = h/2;
      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          dx = x - cx;
          dy = y - cy;
          d = sqrt(dx*dx + dy*dy);
          fd = f*f + d*d;
          nx = round((r*dx/sqrt(fd) + cx));
          ny = round((r*dy/sqrt(fd) + cy));
          if(0<=nx && nx<w && 0<=ny && ny<h) {
            i = (step + x) << 2;
            j = (ny*w + nx) << 2;
            dst[j] = src[i];
            dst[j + 1] = src[i + 1];
            dst[j + 2] = src[i + 2];
            dst[j + 3] = 1; // alpha channel, as flag
          }
        }
      }
      core.interpolation(dstimg, 1);
      return dstimg;
    },
    /* interpolation (destructive!) */
    interpolation : function(img, radius) {
      var w = img.width,
          h = img.height,
          data = img.data,
          r = radius,
          kernel = [1, 2, 1, 2, 4, 2, 1, 2, 1], // 3*3
          threshold = (2*r + 1)*(2*r + 1)/2,
          buff = [0, 0, 0],
          i, j, k, acc, step, kstep, px, py, div;

      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          i = (step + x) << 2;
          if(data[i + 3] !== 1) {
            buff[0] = buff[1] = buff[2] = 0;
            k = 0;
            acc = 0;
            for(var ky=-r; ky<=r; ky++) {
              py = y + ky;
              if(py <= 0 || h <= py) py = y;
              kstep = py*w;
              for(var kx=-r; kx<=r; kx++) {
                px = x + kx;
                if(px <= 0 || w <= px) px = x;
                j = (kstep + px) << 2;
                if(data[j + 3] === 1) {
                  buff[0] += data[j]*kernel[k];
                  buff[1] += data[j + 1]*kernel[k];
                  buff[2] += data[j + 2]*kernel[k];
                  acc += kernel[k];
                  k++;
                }
              }
            }
            if(k > threshold) {
              div = 1/acc;
              data[i] = buff[0]*div;
              data[i + 1] = buff[1]*div;
              data[i + 2] = buff[2]*div;
              data[i + 3] = 1; // as flag
            }
          }
          //data[i + 3] = 255;
        }
      }
    }
  };
  // public API
  Fisheye.transform = core.transform;
}).call(this);

================================================
FILE: cv/image_filter/README.md
================================================
# Image Processing Filters

## description

Image processing filters

* Convolution Filter

[![image_filter](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/convolution_filter.jpg)](http://rest-term.com/labs/html5/convolution.html)

* Symmetric Nearest Neighbor Filter

[![image_filter](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/snn_filter.jpg)](http://rest-term.com/labs/html5/snn.html)

* Jitter Jilter

[![image_filter](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/jitter_filter.jpg)](http://rest-term.com/labs/html5/jitter.html)

### samples
[Convolution Filter][Convolution]

[Symmetric Nearest Neighbor Filter][SNN]

[Jitter Filter][Jitter]

(Tests: Firefox3.6, Safari5.0, Chrome10.0, Opera11.60)

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[Convolution]: http://rest-term.com/labs/html5/convolution.html
[SNN]: http://rest-term.com/labs/html5/snn.html
[Jitter]: http://rest-term.com/labs/html5/jitter.html
[MIT]: http://www.opensource.org/licenses/mit-license.php


================================================
FILE: cv/image_filter/cavin.js
================================================
/**
 * Cavin.js
 * Computer Vision and Image Processing Library for HTML5 Canvas
 */
(function() {
  /**
   * intialize
   */
  var Cavin;        // top-level namespace
  var root = this;  // reference to 'window' or 'global'
  var ctx = null;   // local reference to CanvasRenderingContext2D
  var imgdata = null;  // local reference to ImageData

  // local reference to slice/splice
  var slice = Array.prototype.slice,
      splice = Array.prototype.splice;

  if(typeof exports !== 'undefined') {
    Cavin = exports;  // for CommonJS
  } else {
    Cavin = root.Cavin = {};
  }

  // current version of the library
  Cavin.version = {
    release: '0.1.0',
    date: '2012/03',
  };
  Cavin.toString = function() {
    return "version " + Cavin.version.release + ", released " + Cavin.version.date;
  };

  // set the js library that will be used for DOM manipulation,
  // by default will use jQuery
  var $ = root.jQuery;
  Cavin.setDomLibrary = function(lib) {
    $ = lib;
  };

  /**
   * image I/O modules
   */
  var IO = Cavin.IO = {
    read: function() {
      var args = slice.call(arguments),
          img = new Image(),
          opt = IO._parseOpt(args);
      img.src = opt['path'];
      ctx = document.createElement('canvas').getContext('2d');
      img.addEventListener('load', function(e) {
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        imgdata = ctx.getImageData(0, 0, img.width, img.height);
        opt['success'](imgdata);
      }, false);
      img.addEventListener('error', function(e) {
        opt['error']('can\'t load image: ' + opt['path']);
      }, false)
    },
    write: function(data, target) {
      var ctx;
      if(typeof target === 'string') {
        ctx = document.querySelector(target).getContext('2d');
      } else if(typeof target === 'object') {
        ctx = target;  // CanvasRenderingContext2D
      }
      ctx.putImageData(data, 0, 0);
    },
    getImageData: function(context) {
      var w = context.canvas.width,
          h = context.canvas.height;
      return context.getImageData(0, 0, w, h);
    },
    _parseOpt: function(args) {
      var opt = {};
      // {path:string, success:function, error:function}
      if(args.length === 1 && typeof args[0] === 'object') {
        if(typeof args[0]['path'] !== 'string') {
          throw new Error('string object required: path');
        } else {
          opt['path'] = args[0]['path'];
        }
        if(typeof args[0]['success'] != 'function') {
          throw new Error('function object required: success');
        } else {
          opt['success'] = args[0]['success'];
        }
        if(typeof args[0]['error'] != 'function') {
          throw new Error('function object required: error');
        } else {
          opt['error'] = args[0]['error'];
        }
      }
      // path, callback
      if(args.length === 2 && typeof args[0] === 'string') {
        opt['path'] = args[0];
        if(typeof args[1] != 'function') {
          throw new Error('function object required');
        } else {
          opt['success'] = args[1];
        }
      }
      return opt;
    },
  };
  // aliases
  Cavin.get = Cavin.IO.read;
  Cavin.put = Cavin.IO.write;

  /**
   * image processing filter modules
   */
  var Filter = Cavin.Filter = {
    /* convolution filter (x*x squire kernel) */
    convolution: function(kernel, divisor, bias) {
      var srcimg = imgdata,
          w = srcimg.width,
          h = srcimg.height,
          srcdata = srcimg.data,
          dstimg = ctx.createImageData(w, h),
          dstdata = dstimg.data,
          div = 1/divisor,
          r = Math.sqrt(kernel.length),
          buff = [0, 0, 0],
          i, j, k, v, px, py, step, kstep;
      if(divisor === 0) {
        throw new Error('division zero');
      }
      if(r%2 != 1) {
        throw new Error('square kernel required');
      }
      r = (r - 1)/2;
      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          buff[0] = buff[1] = buff[2] = 0;
          i = (step + x) << 2;
          k = 0;
          // convolution
          for(var ky=-r; ky<=r; ky++) {
            py = y + ky;
            if(py <= 0 || h <= py) py = y;
            kstep = py*w;
            for(var kx=-r; kx<=r; kx++) {
              px = x + kx;
              if(px <= 0 || w <= px) px = x;
              j = (kstep << 2) + (px << 2);
              buff[0] += srcdata[j]*kernel[k];
              buff[1] += srcdata[j + 1]*kernel[k];
              buff[2] += srcdata[j + 2]*kernel[k];
              k++;
            }
          }
          // saturation (for Opera)
          v = buff[0]*div + bias;
          dstdata[i] = v < 0 ? 0 : v > 255 ? 255 : v;
          v = buff[1]*div + bias;
          dstdata[i + 1] = v < 0 ? 0 : v > 255 ? 255 : v;
          v = buff[2]*div + bias;
          dstdata[i + 2] = v < 0 ? 0 : v > 255 ? 255 : v;
          dstdata[i + 3] = 255;
        }
      }
      return dstimg;
    },
    /* box blur filter */
    blur: function(radius) {
      var kernel = [],
          size = (2*radius + 1)*(2*radius + 1);
      for(var i=0; i<size; i++) {
        kernel[i] = 1;
      }
      return Filter.convolution(kernel, size, 0);
    },
    /* gaussian blur filter */
    gaussian: function(radius) {
      var kernel = [],
          size = (2*radius + 1)*(2*radius + 1),
          sigma = 0.849321800288,
          k = 1.0/Math.sqrt(2.0*Math.PI)/sigma,
          f = 0;
      for(var y=-radius; y<=radius; y++) {
        for(var x=-radius; x<=radius; x++) {
          f = k*Math.exp(-(x*x + y*y)/(2*sigma*sigma));
          kernel.push(f);
        }
      }
      return Filter.convolution(kernel, size, 0);
    },
    /* jitter filter */
    jitter: function(amount) {
      var srcimg = imgdata,
          w = srcimg.width,
          h = srcimg.height,
          srcdata = srcimg.data,
          dstimg = ctx.createImageData(w, h),
          dstdata = dstimg.data,
          dx, dy, i, k, step;
      for(var y=0; y<h; y++) {
        step = y*w;
        for(var x=0; x<w; x++) {
          dx = x + Math.round((Math.random() - 0.5)*amount);
          dy = y + Math.round((Math.random() - 0.5)*amount);
          i = (step + x) << 2;
          k = (w*dy + dx) << 2;
          dstdata[i] = srcdata[k];
          dstdata[i + 1] = srcdata[k + 1];
          dstdata[i + 2] = srcdata[k + 2];
          dstdata[i + 3] = 255;
        }
      }
      return dstimg;
    },
    /* symmetric nearest neighbor filter */
    snn: function(radius) {
      var srcimg = imgdata,
          w = srcimg.width,
          h = srcimg.height,
          r = parseInt(radius),
          div = 1.0/((2*r + 1)*(2*r + 1)),
          srcdata = srcimg.data,
          dstimg = ctx.createImageData(w, h),
          dstdata = dstimg.data,
          sumr, sumg, sumb,
          rc, gc, bc, r1, g1, b1, r2, g2, b2,
          pv, pu, xystep, uvstep, delta1, delta2,
          i, j;
      for(var y=0; y<h; y++) {
        xystep = y*w;
        for(var x=0; x<w; x++) {
          i = (xystep + x) << 2;
          sumr = 0, sumg = 0, sumb = 0;
          rc = srcdata[i];
          gc = srcdata[i + 1];
          bc = srcdata[i + 2];
          for(var v=-r; v<=r; v++) {
            uvstep = w*v;
            for(var u=-r; u<=r; u++) {
              j = (uvstep + u) << 2;
              if(srcdata[i + j]) {
                r1 = srcdata[i + j];
                g1 = srcdata[i + j + 1];
                b1 = srcdata[i + j + 2];
              } else {
                r1 = srcdata[i];
                g1 = srcdata[i + 1];
                b1 = srcdata[i + 2];
              }
              if(srcdata[i - j]) {
                r2 = srcdata[i - j];
                g2 = srcdata[i - j + 1];
                b2 = srcdata[i - j + 2];
              } else {
                r2 = srcdata[i];
                g2 = srcdata[i + 1];
                b2 = srcdata[i + 2];
              }
              delta1 = Math.sqrt((rc - r1)*(rc - r1) +
                                 (gc - g1)*(gc - g1) +
                                 (bc - b1)*(bc - b1));
              delta2 = Math.sqrt((rc - r2)*(rc - r2) +
                                 (gc - g2)*(gc - g2) +
                                 (bc - b2)*(bc - b2));
              if(delta1 < delta2) {
                sumr += r1;
                sumg += g1;
                sumb += b1;
              } else {
                sumr += r2;
                sumg += g2;
                sumb += b2;
              }
            }
          }
          dstdata[i] = sumr*div;
          dstdata[i + 1] = sumg*div;
          dstdata[i + 2] = sumb*div;
          dstdata[i + 3] = 255;
        }
      }
      return dstimg;
    },
  };
  /**
   * 2D-features detection modules
   */
  Cavin.Features2D = (function() {
    function Features2D() {}
    Features2D.hlac = function() {
      // todo
    };
    Features2D.orb = function() {
      // todo
    };
    Features2D.surf = function(){
      // in patent
    };
    Features2D.star = function() {
      // todo
    };
    return Features2D;
  })();
  /**
   * Utilities modules
   */
  Cavin.Util = (function() {
    function Util() {}
    Util.hex2rgb = function(hex) {
      var r, g, b;
      if(hex.charAt(0) === "#") hex = hex.substr(1);
      r = parseInt(hex.substr(0, 2), 16);
      g = parseInt(hex.substr(2, 2), 16);
      b = parseInt(hex.substr(4, 2), 16);
      return {r: r, g: g, b: b};
    };
    return Util;
  })();
}).call(this);

================================================
FILE: cv/image_filter/cvsandbox.js
================================================
/**
 * Computer Vision Modules using Sandbox Pattern
 */

/* CV: Sandbox constructor */
function CV() {
  var args = Array.prototype.slice.call(arguments),
      callback = args.pop(),
      modules = (args[0] && typeof args[0] === "string") ? args : args[0],
      i;
  if(!(this instanceof CV)) {
    return new CV(modules, callback);
  }
  if(!modules || modules[0] === "*") {
    modules = [];
    for(i in CV.modules) {
      if(CV.modules.hasOwnProperty(i)) {
        modules.push(i);
      }
    }
  }
  for(i=0; i<modules.length; i++) {
    CV.modules[modules[i]](this);
  }
  callback(this);
}
CV.modules = {}; // modules

/* core module */
CV.modules.core = function(self) {
  // load image file
  self.load = function(source, context) {
    var p = self.constructor.prototype;
    var img = new Image();
    p.ctx = context;
    img.src = source;
    img.addEventListener('load', function() {
      p.ctx.drawImage(img, 0, 0);
      p.bitmapData = p.ctx.getImageData(0, 0, img.width, img.height);
    }, false);
    img.addEventListener('error', function() {
      throw new Error('cannot load image');
    }, false);
  };
  // draw on the canvas
  self.draw = function(data, context) {
    context.putImageData(data, 0, 0);
  };
};

/* image filter module */
CV.modules.filter = function(self) {
  // convolution filter
  self.convolution = function(kernel, divisor, bias) {
    var p = self.constructor.prototype,
        w = p.bitmapData.width,
        h = p.bitmapData.height,
        srcData = p.bitmapData.data,
        dstImg = p.ctx.createImageData(w, h),
        dstData = dstImg.data,
        len = dstData.length,
        r, g, b, i, j, k, step, kStep;
    for(var y=1; y<h-1; y++) {
      step = y*w;
      for(var x=1; x<w-1; x++) {
        r = 0; g = 0; b = 0;
        i = (step + x) << 2;
        k = 0;
        for(var ky=-1; ky<=1; ky++) {
          kStep = ky*w;
          for(var kx=-1; kx<=1; kx++) {
            j = (kStep << 2) + (kx << 2);
            r += srcData[i + j]*kernel[k];
            g += srcData[i + j + 1]*kernel[k];
            b += srcData[i + j + 2]*kernel[k];
            k++;
          }
        }
        dstData[i] = r/divisor + bias;
        dstData[i + 1] = g/divisor + bias;
        dstData[i + 2] = b/divisor + bias;
        dstData[i + 3] = 255;
      }
    }
    for(var l=0; l<len; l++) {
      var value = dstData[l];
      dstData[l] = value<0 ? 0 : value>255 ? 255 : value;
    }
    return dstImg;
  };
  // jitter filter
  self.jitter = function(amount) {
    var p = self.constructor.prototype,
        w = p.bitmapData.width,
        h = p.bitmapData.height,
        srcData = p.bitmapData.data,
        dstImg = p.ctx.createImageData(w, h),
        dstData = dstImg.data,
        len = dstData.length,
        dx, dy, step, i, k;
    for(var y=0; y<h; y++) {
      step = y*w;
      for(var x=0; x<w; x++) {
        dx = x + Math.round((Math.random() - 0.5)*amount);
        dy = y + Math.round((Math.random() - 0.5)*amount);
        i = (step + x) << 2;
        k = (w*dy + dx) << 2;
        dstData[i] = srcData[k];
        dstData[i + 1] = srcData[k + 1];
        dstData[i + 2] = srcData[k + 2];
        dstData[i + 3] = 255;
      }
    }
    return dstImg;
  };
};

/* features2d module */
CV.modules.features2d = function(self) {
  // HLAC
  self.hlac = function() {
    var p = self.constructor.prototype,
        w = p.bitmapData.width,  // bitmapData: ImageData
        h = p.bitmapData.height,
        src = p.bitmapData.data, // CanvasPixelArray
        // mask patterns for HLAC (N:2, 3*3)
        mask = ['000010000','000011000','001010000','010010000','100010000',
                '000111000','001010100','010010010','100010001','001110000',
                '010010100','100010010','000110001','000011100','001010010',
                '010010001','100011000','010110000','100010100','000110010',
                '000010101','000011010','001010001','010011000','101010000'],
        len = mask.length,
        features = [],
        c, i, j, l, step, kstep,
        cmp = 0;

    // mask pattern, feature vector intialize
    for(var k=0; k<len; k++) {
      mask[k] = parseInt(mask[k], 2);
      features[k] = 0;
    }
    // product-sum operation for each mask pattern
    // CanvasPixelArray: [R0,G0,B0,A0,R1,G1,B1,A1, ...]
    for(k=0; k<len; k++) {
      for(var y=1; y<h-1; y++) {
        step = y*w;
        for(var x=1; x<w-1; x++) {
          i = (step + x) << 2;
          if(src[i] === cmp) continue;
          for(var ky=-1, l=8, c=1; ky<=1; ky++) {
            if(c === 0) break;
            kstep = ky*w;
            for(var kx=-1; kx<=1; kx++, l--) {
              j = (kstep + kx) << 2;
              if((mask[k] >> l & 1) && (src[i + j] === cmp)) {
                c = 0;
                break;
              }
            }
          }
          features[k] += c;
        }
      }
    }
    return features;
  };
  self.stardetect = function(param) {
    // TODO
  };
};

/* utilities module */
/* image histogram */
CV.modules.histogram = function(self) {
  // draw histogram on the canvas
  self.drawHistogram = function(bins, context, style) {
    var h = context.canvas.height,
        max = self.getMax(bins),
        len = bins.length,
        step = context.canvas.width/len,
        k = 2;
    style = style || {};
    context.globalAlpha = style['globalAlpha'] || 0.8;
    context.strokeStyle = style['strokeStyle'] || '#00cc66';
    context.lineWidth = style['lineWidth'] || 4;
    for(var i=0; i<len; i++, k+=step) {
      context.beginPath();
      context.moveTo(k, h);
      context.lineTo(k, Math.max(0.0, h - bins[i]*h/max));
      context.stroke();
      context.closePath();
    }
  };
  // calculate histogram intersection
  self.intersection = function(hist1, hist2) {
    if(hist1.length != hist2.length) {
      throw new Error('invalid histogram pair');
    }
    var minsum = 0.0,
        len = hist1.length,
        min = 0, sum1 = 0, sum2 = 0;
    for(var i=0; i<len; i++) {
      min = (hist1[i] < hist2[i]) ? hist1[i] : hist2[i];
      minsum += min;
      sum1 += hist1[i];
      sum2 += hist2[i];
    }
    return (sum1 > sum2) ? minsum/sum1 : minsum/sum2;
  };
  self.addHistogram = function(hist1, hist2) {
    if(hist1.length != hist2.length) {
      throw new Error('invalid histogram pair');
    }
    var newhist = [],
        len = hist1.length;
    for(var i=0; i<len; i++) {
      newhist[i] = hist1[i] + hist2[i];
    }
    return newhist;
  };
  self.getMax = function(bins) {
    var max = 0,
        len = bins.length;
    for(var i=0; i<len; i++) {
      if(bins[i] > max) max = bins[i];
    }
    return max;
  };
};

/* web storage */
CV.modules.storage = function(self) {
  // thin wrapper
  self.getData = function(key) {
    return JSON.parse(window.localStorage[key]);
  };
  self.setData = function(key, value) {
    window.localStorage[key] = JSON.stringify(value);
  };
};


================================================
FILE: cv/lsd/.babelrc
================================================
{
    "presets": ["react", "es2015", "stage-0"],
    "plugins": [
    ],
    "env": {
        "development": {
            "presets": ["react-hmre"],
            "plugins": [["react-transform", {
                "transforms": [{
                    "transform": "react-transform-hmr",
                    "imports": ["react"],
                    "locals": ["module"]
                }]
            }]]
        },
        "production": {
            
        }
    }
}

================================================
FILE: cv/lsd/.eslintignore
================================================
webpack.config.js
dst/


================================================
FILE: cv/lsd/.eslintrc.json
================================================
{
    "env": {
        "browser": true,
        "node": true,
        "commonjs": true,
        "es6": true
    },
    "extends": "eslint:recommended",
    "ecmaFeatures": {
        "jsx": true,
        "modules": true
    },
    "parserOptions": {
        "sourceType": "module"
    },
    "rules": {
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "warn",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ],
        "no-unreachable": [
            "warn"
        ],
        "no-console":"off"
    },
    "plugins": [
        "react"
    ]
}

================================================
FILE: cv/lsd/README.md
================================================
# Line Segment Detector Module

## description

Line detection using Line Segment Detector ([LSD][IPOL]) algorithm

![lsd](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/lsd_apply.jpg)


see also [blog entry][entry]

### demo
[Line Segment Detector Demo](http://rest-term.com/labs/html5/lsd/index.html) [(mirror)](https://secret-nether-01.herokuapp.com/lsd/)

[![lsd_demo](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/lsd_demo.jpg)](http://rest-term.com/labs/html5/lsd/index.html)


## usage in JavaScript (ES2015)
```js
import LSD from './lsd';
// input 8bit gray scale image
import SampleImage from './sample.jpg';

const image = new Image();
image.src = SampleImage;
image.onload = () => {
    const width = image.width;
    const height = image.height;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    canvas.width = width;
    canvas.height = height;
    context.drawImage(image, 0, 0, width, height);
    document.getElementById('content').appendChild(canvas);
    const imageData = context.getImageData(0, 0, width, height);
    const detector = new LSD();
    const lines = detector.detect(imageData);
    console.log('lines: ' + lines.length.toString());
    detector.drawSegments(context, lines);
};
```

### React Component
```js
import React from 'react';
import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import LSDComponent from './lsd_component';
import SampleImage from './sample.jpg';

ReactDOM.render(
    <MuiThemeProvider>
        <LSDComponent src={SampleImage} />
    </MuiThemeProvider>,
    document.getElementById('content')
);
```


license
----------
Copyright &copy; 2017 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[IPOL]: http://www.ipol.im/pub/art/2012/gjmr-lsd/
[entry]: http://rest-term.com/archives/3393/


================================================
FILE: cv/lsd/jsconfig.json
================================================
{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs"
    }
}

================================================
FILE: cv/lsd/line-segment-detector/.gitignore
================================================
node_modules
dst


================================================
FILE: cv/lsd/line-segment-detector/README.md
================================================
# Line Segment Detector Module

## description

Line detection using Line Segment Detector ([LSD][IPOL]) algorithm

![lsd](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/lsd_apply.jpg)


see also [blog entry][entry]

## install

```
npm install line-segment-detector.js
```

- Todo npm publish ready: add package.json, unit test

### demo
[Line Segment Detector Demo](http://rest-term.com/labs/html5/lsd/index.html) [(mirror)](https://secret-nether-5891.herokuapp.com/lsd/)

[![lsd_demo](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/lsd_demo.jpg)](http://rest-term.com/labs/html5/lsd/index.html)


## usage in JavaScript (ES2015)
```js
import LSD from './lsd';
// input 8bit gray scale image
import SampleImage from './sample.jpg';

const image = new Image();
image.src = SampleImage;
image.onload = () => {
    const width = image.width;
    const height = image.height;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    canvas.width = width;
    canvas.height = height;
    context.drawImage(image, 0, 0, width, height);
    document.getElementById('content').appendChild(canvas);
    const imageData = context.getImageData(0, 0, width, height);
    const detector = new LSD();
    const lines = detector.detect(imageData);
    console.log('lines: ' + lines.length.toString());
    detector.drawSegments(context, lines);
};
```

### React Component
```js
import React from 'react';
import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import LSDComponent from './lsd_component';
import SampleImage from './sample.jpg';

ReactDOM.render(
    <MuiThemeProvider>
        <LSDComponent src={SampleImage} />
    </MuiThemeProvider>,
    document.getElementById('content')
);
```


license
----------
Copyright &copy; 2017 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[IPOL]: http://www.ipol.im/pub/art/2012/gjmr-lsd/
[entry]: http://rest-term.com/archives/3393/


================================================
FILE: cv/lsd/line-segment-detector/jsconfig.json
================================================
{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs"
    }
}

================================================
FILE: cv/lsd/line-segment-detector/package.json
================================================
{
  "name": "line-segment-detector.js",
  "version": "1.0.0",
  "description": "Line Segment Detector",
  "main": "./dst/lsd.js",
  "types": "./dst/lsd.d.ts",
  "files": [
    "dst"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prod": "rimraf dst && webpack -p",
    "dev": "rimraf dst && webpack -d",
    "prepublish": "npm run prod"
  },
  "keywords": [],
  "author": "wellflat",
  "license": "MIT",
  "dependencies": {},
  "devDependencies": {
    "eslint": "^4.5.0",
    "rimraf": "^2.6.1",
    "ts-loader": "^2.3.3",
    "typescript": "^2.4.2",
    "webpack": "^3.5.5"
  }
}


================================================
FILE: cv/lsd/line-segment-detector/src/funcs.ts
================================================
import { Edge } from './types';

/**
 * constants and utility math functions
 */

const M_3_2_PI = (3 * Math.PI) / 2;
const M_2__PI = (2 * Math.PI);
const M_LN10 = 2.30258509299404568402;
const NOT_DEF = -1024.0;
const USED = 1;
const NOT_USED = 0;
const RELATIVE_ERROR_FACTOR = 100.0;
const DEG_TO_RADS = Math.PI / 180;
const REFINE_NONE = 0;
const REFINE_STD = 1;
const REFINE_ADV = 2;


const logGamma = (x: number) => x > 15.0 ? logGammaWindschitl(x) : logGammaLanczos(x);

const logGammaWindschitl = (x: number) =>
    0.918938533204673 + (x - 0.5) * Math.log(x) - x
    + 0.5 * x * Math.log(x * Math.sinh(1 / x) + 1 / (810.0 * Math.pow(x, 6.0)));

function logGammaLanczos(x: number) {
    const q = [
        75122.6331530, 80916.6278952, 36308.2951477,
        8687.24529705, 1168.92649479, 83.8676043424,
        2.50662827511
    ];
    let a = (x + 0.5) * Math.log(x + 5.5) - (x + 5.5);
    let b = 0;
    for(let n = 0; n < 7; ++n) {
        a -= Math.log(x + n);
        b += q[n] * Math.pow(x, n);
    }
    return a + Math.log(b);
}

const distSq = (x1: number, x2: number, y1: number, y2: number) =>
    (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);

const dist = (x1: number, x2: number, y1: number, y2: number) => Math.sqrt(distSq(x1, y1, x2, y2));

function angleDiffSigned(a: number, b: number) {
    let diff = a - b;
    const PI = Math.PI;
    while (diff <= -PI) {
        diff += M_2__PI;
    }
    while (diff > PI) {
        diff -= M_2__PI;
    }
    return diff;
}

function angleDiff(a: number, b: number) {
    const value = angleDiffSigned(a, b);
    return value >= 0  ? value : -value;
}

function doubleEqual(a: number, b: number) {
    if (a == b) {
        return true;
    }
    const diff = a - b;
    const absDiff = diff >= 0 ? diff : -diff;
    const aa = a >= 0 ? a : - a;
    const bb = b >= 0 ? b : - b;
    let absMax = (aa > bb) ? aa : bb;
    const MIN_VALUE = Number.MIN_VALUE;
    if (absMax < MIN_VALUE) {
        absMax = MIN_VALUE;
    }
    return (absDiff / absMax) <= (RELATIVE_ERROR_FACTOR * Number.EPSILON);
}

function AsmallerB_XoverY(a: Edge, b: Edge) {
    if (a.p.x == b.p.x) {
        return Number(a.p.y < b.p.y);
    } else {
        return Number(a.p.x < b.p.x);
    }
}

export {
    M_3_2_PI, M_2__PI, M_LN10,
    NOT_DEF, USED, NOT_USED, RELATIVE_ERROR_FACTOR, DEG_TO_RADS,
    REFINE_NONE, REFINE_STD, REFINE_ADV,
    logGamma, dist, distSq, angleDiff, doubleEqual, AsmallerB_XoverY
};


================================================
FILE: cv/lsd/line-segment-detector/src/lsd.ts
================================================
/**
 * Line Segment Detector (LSD) module
 * @author https://github.com/wellflat
 */

import * as funcs from './funcs';
import { Vec4, Point, CoorList, RegionPoint, Rect, Edge } from './types';

/**
 * Create a LineSegmentDetector object.
 * Specifying scale, number of subdivisions for the image,
 * should the lines be refined and other constants as follows:
 *
 * @param refine       How should the lines found be refined?
 *                      REFINE_NONE - No refinement applied.
 *                      REFINE_STD  - Standard refinement is applied. E.g. breaking arches into smaller line approximations.
 *                      REFINE_ADV  - Advanced refinement. Number of false alarms is calculated,
 *                                    lines are refined through increase of precision, decrement in size, etc.
 * @param scale        The scale of the image that will be used to find the lines. Range (0..1].
 * @param sigmaScale   Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale.
 * @param quant        Bound to the quantization error on the gradient norm.
 * @param angTh        Gradient angle tolerance in degrees.
 * @param logEps       Detection threshold: -log10(NFA) > _log_eps
 * @param densityTh    Minimal density of aligned region points in rectangle.
 * @param nBins        Number of bins in pseudo-ordering of gradient modulus.
 */
export default class LSD {
    image?: ImageData;
    private imageData?: Uint8ClampedArray;
    width = 0;
    height = 0;
    list: CoorList[] = [];
    angles?: Float64Array;
    modgrad?: Float64Array;
    used?: Uint8Array;

    constructor(
        public refineType = funcs.REFINE_NONE, public scale = 0.8, public sigmaScale = 0.6, public quant = 2.0,
        public angTh = 22.5, public logEps = 0.0, public densityTh = 0.7, public nBins = 1024
    ) { }
    /**
     * Detect lines in the input image.
     * @param {ImageData} image
     * @return {Vec4[]}
     */
    detect(image: ImageData) {
        this.image = image;
        this.width = image.width;
        this.height = image.height;
        const lines = this.lsd();
        return lines;
    }
    /**
     * Draws the line segments on a given image.
     * @param {CanvasRenderingContext2D} context
     * @param {Vec4[]} lines
     * @param {string} color
     */
    drawSegments(context: CanvasRenderingContext2D, lines: Vec4[], color = '#ff0000') {
        context.strokeStyle = color;
        context.lineWidth = 1;
        lines.forEach(v => {
            context.beginPath();
            context.moveTo(v.x1, v.y1);
            context.lineTo(v.x2, v.y2);
            context.stroke();
            context.closePath();
        });
    }

    /**
     * for debug
     * @param {CanvasRenderingContext2D} context
     */
    putImageData(context: CanvasRenderingContext2D) {
        let src = this.imageData,
            image = context.createImageData(this.width, this.height),
            dst = image.data,
            len = image.data.length;
        if (!src) throw new Error('imageData required'); // type guard
        for (let i = 0; i < len; i += 4) {
            dst[i] = dst[i + 1] = dst[i + 2] = src[i/4];
            dst[i + 3] = 255;
        }
        context.putImageData(image, 0, 0);
    }
    /**
     * @return {Vec4[]}  Return: A vector of Vec4f elements specifying the beginning and ending point of a line.
     *                   Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
     *                   Returned lines are strictly oriented depending on the gradient.
     */
    lsd() {
        if (!this.image || !this.angles) throw new Error('image and angles required'); // type guard
        /** @type {Vec4[]} */
        let lines = [];
        const prec = Math.PI * this.angTh / 180;
        const p = this.angTh / 180;
        const rho = this.quant / Math.sin(prec);
        if (this.scale != 1) {
            const sigma = this.scale < 1 ? this.sigmaScale / this.scale : this.sigmaScale;
            const sprec = 3;
            const h = Math.ceil(sigma * Math.sqrt(2 * sprec * Math.log(10.0)));
            const kSize = 1 + 2 * h;
            const reshaped = this.reshape(this.image);
            this.imageData = this.gaussianBlur(reshaped, kSize, sigma);
            this.computeLevelLineAngles(rho, this.nBins);
        } else {
            this.imageData = this.reshape(this.image);
            this.computeLevelLineAngles(rho, this.nBins);
        }

        const LOG_NT = 5 * (Math.log10(this.width) + Math.log10(this.height)) / 2 + Math.log10(11.0);
        const minRegSize = -LOG_NT / Math.log10(p);
        this.used = new Uint8Array(this.imageData.length);
        for (let i = 0, listSize = this.list.length; i < listSize; i++) {
            const point = this.list[i].p;
            if ((this.at(this.used, point) === funcs.NOT_USED) &&
                (this.at(this.angles, point) !== funcs.NOT_DEF)) {
                let regAngle = 0.0;
                let reg: RegionPoint[] = [];
                regAngle = this.regionGrow(this.list[i].p, reg, regAngle, prec);
                if (reg.length < minRegSize) {
                    continue;
                }
                let rect = new Rect();
                this.region2Rect(reg, regAngle, prec, p, rect);
                let logNfa = -1;
                if (this.refineType > funcs.REFINE_NONE) {
                    if (!this.refine(reg, regAngle, prec, p, rect, this.densityTh)) {
                        continue;
                    }
                    if (this.refineType >= funcs.REFINE_ADV) {
                        logNfa = this.improveRect(rect);
                        if (logNfa <= this.logEps) {
                            continue;
                        }
                    }
                }
                rect.x1 += 0.5;
                rect.y1 += 0.5;
                rect.x2 += 0.5;
                rect.y2 += 0.5;
                /*
                if (this.scale != 1) {
                    rect.x1 /= this.scale;
                    rect.y1 /= this.scale;
                    rect.x2 /= this.scale;
                    rect.y2 /= this.scale;
                    rect.width /= this.scale;
                }
                */
                lines.push(new Vec4(rect.x1, rect.y1, rect.x2, rect.y2));
            }
        }
        return lines;
    }

    /**
     * @param {number} threshold The minimum value of the angle that is considered defined, otherwise NOTDEF
     * @param {number} nBins     The number of bins with which gradients are ordered by, using bucket sort.
     */
    computeLevelLineAngles(threshold: number, nBins: number) {
        const imageData = this.imageData;
        if (!imageData) throw new Error('imageData required'); // type guard
        const width = this.width;
        const height = this.height;
        this.angles = new Float64Array(imageData.length);
        this.modgrad = new Float64Array(imageData.length);
        this.angles = this.setRow(this.angles, height - 1, funcs.NOT_DEF);
        this.angles = this.setCol(this.angles, width - 1, funcs.NOT_DEF);
        let maxGrad = -1.0;
        for (let y = 0; y < height - 1; y++) {
            const step = y * width;
            const nextStep = (y + 1) * width;
            for (let x = 0; x < width - 1; x++) {
                const DA = imageData[x + 1 + nextStep] - imageData[x + step];
                const BC = imageData[x + 1 + step] - imageData[x + nextStep];
                const gx = DA + BC;
                const gy = DA - BC;
                const norm = Math.sqrt((gx * gx + gy * gy) / 4.0);
                this.modgrad[x + step] = norm;
                if (norm <= threshold) {
                    this.angles[x + step] = funcs.NOT_DEF;
                } else {
                    this.angles[x + step] = Math.atan2(gx, -gy);
                    if (norm > maxGrad) {
                        maxGrad = norm;
                    }
                }
            }
        }
        /** @type {CoorList[]} */
        let rangeS = [];
        rangeS.length = nBins;
        /** @type {CoorList[]} */
        let rangeE = [];
        rangeE.length = nBins;
        let count = 0;
        const binCoef = (maxGrad > 0) ? (nBins - 1) / maxGrad : 0;
        for (let y = 0; y < height - 1; y++) {
            let step = y * width;
            for (let x = 0; x < width - 1; x++) {
                let i = Math.floor(this.modgrad[x + step] * binCoef);
                if (!rangeE[i]) {
                    this.list[count] = new CoorList();
                    rangeE[i] = rangeS[i] = this.list[count];
                    count++;
                } else {
                    this.list[count] = new CoorList();
                    rangeE[i] = this.list[count];
                    rangeE[i].next = this.list[count];
                    count++;
                }
                rangeE[i].p = new Point(x, y);
                rangeE[i].next = null;
            }
        }
        let idx = nBins - 1;
        for (; idx > 0 && !rangeS[idx]; idx--) {
            // do nothing.
        }
        let start = rangeS[idx];
        let endIdx = idx;
        if (start) {
            while (idx > 0) {
                idx--;
                if (rangeS[idx]) {
                    rangeE[endIdx].next = rangeS[idx];
                    rangeE[endIdx] = rangeE[idx];
                    endIdx = idx;
                }
            }
        }
    }

    regionGrow(s: Point, reg: RegionPoint[], regAngle: number, prec: number) {
        if (!this.used || !this.angles || !this.modgrad) throw new Error('used, angles and modgrad required'); // type guard
        let seed = new RegionPoint();
        seed.x = s.x;
        seed.y = s.y;
        seed.used = this.at(this.used, s);
        regAngle = this.at(this.angles, s);
        seed.angle = regAngle;
        seed.modgrad = this.at(this.modgrad, s);
        seed.used = funcs.USED;
        reg.push(seed);
        let sumdx = Math.cos(regAngle);
        let sumdy = Math.sin(regAngle);

        for (let i = 0; i < reg.length; i++) {
            const rpoint = reg[i],
                xxMin = Math.max(rpoint.x - 1, 0),
                xxMax = Math.min(rpoint.x + 1, this.width - 1),
                yyMin = Math.max(rpoint.y - 1, 0),
                yyMax = Math.min(rpoint.y + 1, this.height - 1);
            for (let yy = yyMin; yy <= yyMax; yy++) {
                const step = yy * this.width;
                for (let xx = xxMin; xx <= xxMax; xx++) {
                    let isUsed = this.used[xx + step];
                    if (isUsed != funcs.USED && this.isAligned(xx, yy, regAngle, prec)) {
                        const angle = this.angles[xx + step];
                        isUsed = funcs.USED;
                        this.used[xx + step] = funcs.USED;
                        let regionPoint = new RegionPoint(
                            xx, yy, angle, this.modgrad[xx + step], isUsed
                        );
                        reg.push(regionPoint);
                        sumdx += Math.cos(angle);
                        sumdy += Math.sin(angle);
                        regAngle = Math.atan2(sumdy, sumdx);
                    }
                }
            }
        }
        return regAngle;
    }

    isAligned(x: number, y: number, theta: number, prec: number) {
        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
            return false;
        }
        const a = this.angles![x + y * this.width];
        if (a === funcs.NOT_DEF) {
            return false;
        }
        let nTheta = theta - a;
        if (nTheta < 0) {
            nTheta = -nTheta;
        }
        if (nTheta > funcs.M_3_2_PI) {
            nTheta -= funcs.M_2__PI;
            if (nTheta < 0) {
                nTheta = -nTheta;
            }
        }
        return nTheta <= prec;
    }

    region2Rect(reg: RegionPoint[], regAngle: number, prec: number, p: number, rect: Rect) {
        let x = 0, y = 0, sum = 0;
        for (let i = 0; i < reg.length; i++) {
            const pnt = reg[i];
            const weight = pnt.modgrad;
            x += pnt.x * weight;
            y += pnt.y * weight;
            sum += weight;
        }
        if (sum <= 0) {
            throw new Error('weighted sum must differ from 0');
        }
        x /= sum;
        y /= sum;
        const theta = this.getTheta(reg, x, y, regAngle, prec);
        const dx = Math.cos(theta);
        const dy = Math.sin(theta);
        let lMin = 0, lMax = 0, wMin = 0, wMax = 0;
        for (let i = 0; i < reg.length; i++) {
            let regdx = reg[i].x - x;
            let regdy = reg[i].y - y;
            let l = regdx * dx + regdy * dy;
            let w = -regdx * dy + regdy * dx;
            if (l > lMax) {
                lMax = l;
            } else if (l < lMin) {
                lMin = l;
            }
            if (w > wMax) {
                wMax = w;
            } else if (w < wMin) {
                wMin = w;
            }
        }
        rect.x1 = x + lMin * dx;
        rect.y1 = y + lMin * dy;
        rect.x2 = x + lMax * dx;
        rect.y2 = y + lMax * dy;
        rect.width = wMax - wMin;
        rect.x = x;
        rect.y = y;
        rect.theta = theta;
        rect.dx = dx;
        rect.dy = dy;
        rect.prec = prec;
        rect.p = p;
        if (rect.width < 1.0) {
            rect.width = 1.0;
        }
    }

    getTheta(reg: RegionPoint[], x: number, y: number, regAngle: number, prec: number) {
        let ixx = 0.0,
            iyy = 0.0,
            ixy = 0.0;
        for (let i = 0; i < reg.length; i++) {
            const regx = reg[i].x;
            const regy = reg[i].y;
            const weight = reg[i].modgrad;
            let dx = regx - x;
            let dy = regy - y;
            ixx += dy * dy * weight;
            iyy += dx * dx * weight;
            ixy -= dx * dy * weight;
        }
        let check = (funcs.doubleEqual(ixx, 0) && funcs.doubleEqual(iyy, 0) && funcs.doubleEqual(ixy, 0));
        if (check) {
            throw new Error('check if inertia matrix is null');
        }
        let lambda = 0.5 * (ixx + iyy - Math.sqrt((ixx - iyy) * (ixx - iyy) + 4.0 * ixy * ixy));
        let theta = (Math.abs(ixx) > Math.abs(iyy)) ? Math.atan2(lambda - ixx, ixy) :
            Math.atan2(ixy, lambda - iyy);
        if (funcs.angleDiff(theta, regAngle) > prec) {
            theta += Math.PI;
        }
        return theta;
    }

    refine(reg: RegionPoint[], regAngle: number, prec: number, p: number, rect: Rect, densityTh: number) {
        let density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
        if (density >= densityTh) {
            return true;
        }
        let xc = reg[0].x;
        let yc = reg[0].y;
        const angC = reg[0].angle;
        let sum = 0, sSum = 0, n = 0;
        for (let i = 0; i < reg.length; i++) {
            reg[i].used = funcs.NOT_USED;
            if (funcs.dist(xc, yc, reg[i].x, reg[i].y) < rect.width) {
                const angle = reg[i].angle;
                let angD = funcs.angleDiff(angle, angC);
                sum += angD;
                sSum += angD * angD;
                n++;
            }
            let meanAngle = sum / n;
            let tau = 2.0 * Math.sqrt((sSum - 2.0 * meanAngle * sum) / n + meanAngle * meanAngle);
            this.regionGrow(new Point(reg[0].x, reg[0].y), reg, regAngle, tau);
            if (reg.length < 2) {
                return false;
            }
            this.region2Rect(reg, regAngle, prec, p, rect);
            density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
            if (density < densityTh) {
                return this.reduceRegionRadius(reg, regAngle, prec, p, rect, density, densityTh);
            } else {
                return true;
            }
        }
        return false; // type guard (unreachable)
    }

    reduceRegionRadius(reg: RegionPoint[], regAngle: number, prec: number, p: number, rect: Rect, density: number, densityTh: number) {
        let xc = reg[0].x;
        let yc = reg[0].y;
        let radSq1 = funcs.distSq(xc, yc, rect.x1, rect.y1);
        let radSq2 = funcs.distSq(xc, yc, rect.x2, rect.y2);
        let radSq = radSq1 > radSq2 ? radSq1 : radSq2;
        while (density < densityTh) {
            radSq *= 0.75 * 0.75; // reduce region's radius to 75%
            for (let i = 0; i < reg.length; i++) {
                if (funcs.distSq(xc, yc, reg[i].x, reg[i].y) > radSq) {
                    // remove point from the region
                    reg[i].used = funcs.NOT_USED;
                    const tmp = reg[i];
                    reg[i] = reg[reg.length - 1];
                    reg[reg.length - 1] = tmp;
                    reg.pop();
                    --i;
                }
            }
            if (reg.length < 2) {
                return false;
            }
            this.region2Rect(reg, regAngle, prec, p, rect);
            density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
        }
        return true;
    }

    improveRect(rect: Rect) {
        let delta = 0.5;
        let delta2 = delta / 2.0;
        let logNfa = this.rectNfa(rect);
        if (logNfa > this.logEps) {
            return logNfa;
        }
        let r = new Rect();
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            r.p /= 2;
            r.prec = r.p * Math.PI;
            let logNfaNew = this.rectNfa(rect);
            if (logNfaNew > logNfa) {
                logNfa = logNfaNew;
                rect.copy(r);
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.width -= delta;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.x1 -= -r.dy * delta2;
                r.y1 -= r.dx * delta2;
                r.x2 -= -r.dy * delta2;
                r.y2 -= r.dx * delta2;
                r.width -= delta;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.p /= 2;
                r.prec = r.p * Math.PI;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        return logNfa;
    }

    rectNfa(rect: Rect) {
        let totalPts = 0,
            algPts = 0,
            halfWidth = rect.width / 2.0,
            dyhw = rect.dy * halfWidth,
            dxhw = rect.dx * halfWidth,
            orderedX = [
                new Edge(),
                new Edge(),
                new Edge(),
                new Edge()
            ],
            minY = orderedX[0],
            maxY = orderedX[0];
        orderedX[0].p.x = rect.x1 - dyhw;
        orderedX[0].p.y = rect.y1 + dxhw;
        orderedX[1].p.x = rect.x2 - dyhw;
        orderedX[1].p.y = rect.y2 + dxhw;
        orderedX[2].p.x = rect.x2 + dyhw;
        orderedX[2].p.y = rect.y2 - dxhw;
        orderedX[3].p.x = rect.x1 + dyhw;
        orderedX[3].p.y = rect.y1 - dxhw;

        orderedX.sort(funcs.AsmallerB_XoverY);

        for (let i = 1; i < 4; i++) {
            if (minY.p.y > orderedX[i].p.y) {
                minY = orderedX[i];
            }
            if (maxY.p.y < orderedX[i].p.y) {
                maxY = orderedX[i];
            }
        }
        minY.taken = true;
        let leftmost = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!leftmost) {
                    leftmost = orderedX[i];
                } else if (leftmost.p.x > orderedX[i].p.x) {
                    leftmost = orderedX[i];
                }
            }
        }
        if (!leftmost) throw new Error('leftmost error'); // type guard
        leftmost.taken = true;
        let rightmost = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!rightmost) {
                    rightmost = orderedX[i];
                } else if (rightmost.p.x < orderedX[i].p.x) {
                    rightmost = orderedX[i];
                }
            }
        }
        if (!rightmost) throw new Error('rightmost error'); // type guard
        rightmost.taken = true;
        let tailp = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!tailp) {
                    tailp = orderedX[i];
                } else if (tailp.p.x > orderedX[i].p.x) {
                    tailp = orderedX[i];
                }
            }
        }
        if (!tailp) throw new Error('tailp error'); // type guard
        tailp.taken = true;
        let flstep = (minY.p.y != leftmost.p.y) ?
            (minY.p.x + leftmost.p.x) / (minY.p.y - leftmost.p.y) : 0;
        let slstep = (leftmost.p.y != tailp.p.x) ?
            (leftmost.p.x = tailp.p.x) / (leftmost.p.y - tailp.p.x) : 0;
        let frstep = (minY.p.y != rightmost.p.y) ?
            (minY.p.x - rightmost.p.x) / (minY.p.y - rightmost.p.y) : 0;
        let srstep = (rightmost.p.y != tailp.p.x) ?
            (rightmost.p.x - tailp.p.x) / (rightmost.p.y - tailp.p.x) : 0;
        let lstep = flstep, rstep = frstep;
        let leftX = minY.p.x, rightX = minY.p.x;
        let minIter = minY.p.y;
        let maxIter = maxY.p.y;
        for (let y = minIter; y <= maxIter; y++) {
            if (y < 0 || y >= this.height) {
                continue;
            }
            for (let x = leftX; x <= rightX; x++) {
                if (x < 0 || x >= this.width) {
                    continue;
                }
                totalPts++;
                if (this.isAligned(x, y, rect.theta, rect.prec)) {
                    algPts++;
                }
            }
            if (y >= leftmost.p.y) {
                lstep = slstep;
            }
            if (y >= rightmost.p.y) {
                rstep = srstep;
            }
            leftX += lstep;
            rightX += rstep;
        }
        return this.nfa(totalPts, algPts, rect.p);
    }

    nfa(n: number, k: number, p: number) {
        const LOG_NT =  5 * (Math.log10(this.width) + Math.log10(this.height)) / 2 + Math.log10(11.0);
        if (n == 0 || k == 0) {
            return -LOG_NT;
        }
        if (n == k) {
            return -LOG_NT - n * Math.log10(p);
        }
        let pTerm = p / (1 - p);
        let log1Term = (n + 1) - funcs.logGamma(k + 1)
            - funcs.logGamma(n - k + 1)
            + k * Math.log(p) + (n - k) * Math.log(1.0 - p);
        let term = Math.exp(log1Term);
        if (funcs.doubleEqual(term, 0)) {
            if (k > n * p) {
                return -log1Term / funcs.M_LN10 - LOG_NT;
            } else {
                return -LOG_NT;
            }
        }
        let binTail = term;
        let tolerance = 0.1;
        for (let i = k + 1; i <= n; i++) {
            let binTerm = (n - i + 1) / i;
            let multTerm = binTerm * pTerm;
            term *= multTerm;
            binTail += term;
            if (binTerm < 1) {
                let err = term * ((1 - Math.pow(multTerm, (n - i + 1))) / (1 - multTerm) - 1);
                if (err < tolerance * Math.abs(-Math.log10(binTail) - LOG_NT) * binTail) {
                    break;
                }
            }
        }
        return -Math.log10(binTail) - LOG_NT;
    }

    gaussianBlur(imageData: Uint8ClampedArray, kSize: number, sigma: number) {
        let width = this.width,
            height = this.height,
            src = imageData,
            ctx = document.createElement('canvas').getContext('2d'),
            tmp = ctx!.createImageData(width, height),
            dst = null,
            kernel = this.getGaussianKernel(kSize, sigma),
            r = (kSize - 1) / 2;
        const tmp2 = this.reshape(tmp);
        dst = new Uint8ClampedArray(tmp2.length);
        // separate 2d-filter
        for (let y = 0; y < height; y++) {
            let step = y * width;
            for (let x = 0; x < width; x++) {
                let buff = 0;
                let i = x + step;
                let k = 0;
                for (let kx = -r; kx <= r; kx++) {
                    let px = x + kx;
                    if (px <= 0 || width <= px) {
                        px = x;
                    }
                    let j = px + step;
                    buff += src[j] * kernel[k];
                    k++;
                }
                tmp2[i] = buff;
            }
        }

        for (let x = 0; x < width; x++) {
            for (let y = 0; y < height; y++) {
                let step = y * width;
                let buff = 0;
                let i = x + step;
                let k = 0;
                for (let ky = -r; ky <= r; ky++) {
                    let py = y + ky;
                    let kStep = ky * width;
                    if (py <= 0 || height <= py) {
                        py = y;
                        kStep = 0;
                    }
                    let j = i + kStep;
                    buff += tmp2[j] * kernel[k];
                    k++;
                }
                dst[i] = buff;
            }
        }
        return dst;
    }

    getGaussianKernel(kSize: number, sigma: number) {
        // 1d-kernel
        let kernel = [];
        let sigmaX = sigma > 0 ? sigma : ((kSize - 1) * 0.5 - 1) * 0.3 + 0.8;
        let scale2X = -0.5 / (sigmaX * sigmaX);
        let sum = 0.0;
        for (let i = 0; i < kSize; i++) {
            let x = i - (kSize - 1) * 0.5;
            kernel[i] = Math.exp(scale2X * x * x);
            sum += kernel[i];
        }
        sum = 1. / sum;
        for (let i = 0; i < kSize; i++) {
            kernel[i] *= sum;
        }
        return kernel;
    }

    reshape(image: ImageData) {
        let src = image.data;
        let reshaped = new Uint8ClampedArray(src.length / 4);
        let len = reshaped.length;
        for (let i = 0; i < len; i++) {
            reshaped[i] = src[i * 4];
        }
        return reshaped;
    }

    at(data: Uint8Array|Float64Array, p: Point) {
        return data[p.x + (p.y * this.width)];
    }

    row(data: Float64Array, rowIndex: number) {
        let i = rowIndex * this.width;
        return data.subarray(i, i + this.width);
    }

    setRow(data: Float64Array, index: number, value: number) {
        let from = index * this.width;
        let to = from + this.width;
        for (let i = from; i < to; i++) {
            data[i] = value;
        }
        return data;
    }

    setCol(data: Float64Array, index: number, value: number) {
        let to = this.height * this.width;
        let step = this.width;
        for (let i = index; i < to; i += step) {
            data[i] = value;
        }
        return data;
    }
}

================================================
FILE: cv/lsd/line-segment-detector/src/types.ts
================================================
class Vec4 {
    constructor(public x1 = 0, public y1 = 0, public x2 = 0, public y2 = 0) { }
}

class Point {
    constructor(public x = 0.0, public y = 0.0) { }
}

class CoorList {
    p: Point;
    next: CoorList | null;

    constructor() {
        this.p = new Point();
    }
}

class RegionPoint {
    constructor(public x = 0, public y = 0, public angle = 0.0, public modgrad = 0.0, public used?: number) { }
}

class Rect {
    constructor(
        public x1 = 0, public y1 = 0, public x2 = 0, public y2 = 0,
        public width = 0, public height = 0, public x = 0, public y = 0, public theta = 0,
        public dx = 0, public dy = 0, public prec = 0, public p = 0
    ) { }

    copy(rect: Rect) {
        this.x1 = rect.x1;
        this.y1 = rect.y1;
        this.x2 = rect.x2;
        this.y2 = rect.y2;
        this.width = rect.width;
        this.height = rect.height;
        this.x = rect.x;
        this.y = rect.y;
        this.theta = rect.theta;
        this.dx = rect.dx;
        this.dy = rect.dy;
        this.prec = rect.prec;
        this.p = rect.p;
    }
}

class Edge {
    p: Point;
    taken?: boolean;

    constructor() {
        this.p = new Point();
    }
}

export {
    Vec4, Point, CoorList, RegionPoint, Rect, Edge
};


================================================
FILE: cv/lsd/line-segment-detector/tsconfig.json
================================================
{
    "compileOnSave": true,
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "declaration": true,
        "noImplicitAny": true,
        "noImplicitThis": true,
        "noImplicitReturns": true,
        "noImplicitUseStrict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "preserveConstEnums": true,
        "sourceMap": true,
        "strictNullChecks": true,
        "outDir": "",
        "lib": [
            "dom",
            "es2015"
        ]
    },
    "exclude": [
        "node_modules",
        "dst"
    ]
}


================================================
FILE: cv/lsd/line-segment-detector/webpack.config.js
================================================
const webpack = require('webpack');
const path = require('path');

module.exports = {
    entry: path.join(__dirname, './src/lsd.ts'),
    output: {
        path: path.join(__dirname, './dst'),
        filename: 'lsd.js',
        library: 'lineSegmentDetector',
        libraryTarget: 'umd'
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'ts-loader'
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.ts']
    },
    devtool: 'source-map'
};


================================================
FILE: cv/lsd/package.json
================================================
{
  "name": "lsd",
  "version": "1.0.0",
  "description": "LSD: Line Segment Detector",
  "main": "src/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prod": "node_modules/.bin/webpack -p",
    "dev": "node_modules/.bin/webpack -d",
    "start": "node_modules/.bin/webpack-dev-server --hot --inline"
  },
  "keywords": [],
  "author": "wellflat",
  "license": "ISC",
  "babel": {
    "presets": [
      "es2015",
      "react"
    ]
  },
  "dependencies": {
    "material-ui": "^0.17.4",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-tap-event-plugin": "^2.0.1"
  },
  "devDependencies": {
    "babel": "^6.23.0",
    "babel-core": "^6.21.0",
    "babel-loader": "^9.1.2",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-react-hmre": "^1.1.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-register": "^6.18.0",
    "eslint": "^4.18.2",
    "eslint-plugin-react": "^6.9.0",
    "file-loader": "^0.11.0",
    "html-loader": "^0.4.4",
    "html-webpack-plugin": "^5.5.0",
    "url-loader": "^0.5.7",
    "webpack": "^5.76.0",
    "webpack-dev-server": ">=4.11.1"
  }
}


================================================
FILE: cv/lsd/src/app.js
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import Paper from 'material-ui/Paper';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
import LSDComponent from './lsd_component';
import GardenImage from './gardenterrace_gray.jpg';
import MidtownImage from './midtown_gray.jpg';
import BuildingImage from './building_gray.jpg';
import TokyoImage from './tokyostation_gray.jpg';

injectTapEventPlugin();

const style = {
    appBar: {
        margin: '10px 0 10px 0'
    },
    paper: {
        display: 'inline',
        margin: '15px'
    },
    radio: {
        fontSize: '1em',
    }
};

const App = props => (
    <MuiThemeProvider>
        <div>
            <AppBar title='Line Segment Detector Demo' style={style.appBar}
                showMenuIconButton={false} />
            <LSDComponent src={props.src} />
            <Paper style={style.paper}>
                <RadioButtonGroup name='inputImage' defaultSelected='image1'
                    onChange={e => changeImage(e)} style={style.radio}>
                    <RadioButton value='image1' label='Building' />
                    <RadioButton value='image2' label='Tokyo Midtown' />
                    <RadioButton value='image3' label='Tokyo Garden Terrace' />
                    <RadioButton value='image4' label='Tokyo Station' />
                </RadioButtonGroup>
            </Paper>
        </div>
    </MuiThemeProvider>
);
 
ReactDOM.render(
    <App src={BuildingImage} />,
    document.getElementById('content')
);

const changeImage = e => {
    const target = e.target.value;
    let image = null;
    switch (target) {
        case 'image1':
            image = BuildingImage;
            break;
        case 'image2':
            image = MidtownImage;
            break;
        case 'image3':
            image = GardenImage;
            break;
        case 'image4':
            image = TokyoImage;
            break;
    }
    
    ReactDOM.render(
        <App src={image} />,
        document.getElementById('content')
    );
}

/*
const image = new Image();
image.src = BuildingImage;
image.onload = () => {
    const width = image.width;
    const height = image.height;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    canvas.width = width;
    canvas.height = height;
    context.drawImage(image, 0, 0, width, height);
    document.getElementById('content').appendChild(canvas);
    const imageData = context.getImageData(0, 0, width, height);
    let scale = 0.8;
    const detector = new LSD(0, scale);
    const lines = detector.detect(imageData);
    console.log('lines: ' + lines.length.toString());
    detector.drawSegments(context, lines);
};
*/


================================================
FILE: cv/lsd/src/funcs.js
================================================
/**
 * constants and utility math functions
 */

const M_3_2_PI = (3 * Math.PI) / 2;
const M_2__PI = (2 * Math.PI);
const M_LN10 = 2.30258509299404568402;
const NOT_DEF = -1024.0;
const USED = 1;
const NOT_USED = 0;
const RELATIVE_ERROR_FACTOR = 100.0;
const DEG_TO_RADS = Math.PI / 180;
const REFINE_NONE = 0;
const REFINE_STD = 1;
const REFINE_ADV = 2;


const logGamma = x => x > 15.0 ? logGammaWindschitl(x) : logGammaLanczos(x);

const logGammaWindschitl = x =>
    0.918938533204673 + (x - 0.5) * Math.log(x) - x
    + 0.5 * x * Math.log(x * Math.sinh(1 / x) + 1 / (810.0 * Math.pow(x, 6.0)));

function logGammaLanczos(x) {
    const q = [
        75122.6331530, 80916.6278952, 36308.2951477,
        8687.24529705, 1168.92649479, 83.8676043424,
        2.50662827511
    ];
    let a = (x + 0.5) * Math.log(x + 5.5) - (x + 5.5);
    let b = 0;
    for(let n = 0; n < 7; ++n) {
        a -= Math.log(x + n);
        b += q[n] * Math.pow(x, n);
    }
    return a + Math.log(b);
}

const distSq = (x1, x2, y1, y2) =>
    (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);

const dist = (x1, x2, y1, y2) => Math.sqrt(distSq(x1, y1, x2, y2));


/**
 * @param {number} a
 * @param {number} b
 * @return {number}
 */
function angleDiffSigned(a, b) {
    let diff = a - b;
    const PI = Math.PI;
    while (diff <= -PI) {
        diff += M_2__PI;
    }
    while (diff > PI) {
        diff -= M_2__PI;
    }
    return diff;
}

/**
 * @param {number} a
 * @param {number} b
 * @return {number}
 */
function angleDiff(a, b) {
    const value = angleDiffSigned(a, b);
    return value >= 0  ? value : -value;
}

/**
 * @param {number} a
 * @param {number} b
 * @return {number}
 */
function doubleEqual(a, b) {
    if (a == b) {
        return true;
    }
    const diff = a - b;
    const absDiff = diff >= 0 ? diff : -diff;
    const aa = a >= 0 ? a : - a;
    const bb = b >= 0 ? b : - b;
    let absMax = (aa > bb) ? aa : bb;
    const MIN_VALUE = Number.MIN_VALUE;
    if (absMax < MIN_VALUE) {
        absMax = MIN_VALUE;
    }
    return (absDiff / absMax) <= (RELATIVE_ERROR_FACTOR * Number.EPSILON);
}

/**
 * 
 * @param {Edge} a
 * @param {Edge} b
 */
function AsmallerB_XoverY(a, b) {
    if (a.p.x == b.p.x) {
        return a.p.y < b.p.y;
    } else {
        return a.p.x < b.p.x;
    }
}

export {
    M_3_2_PI, M_2__PI, M_LN10,
    NOT_DEF, USED, NOT_USED, RELATIVE_ERROR_FACTOR, DEG_TO_RADS,
    REFINE_NONE, REFINE_STD, REFINE_ADV,
    logGamma, dist, distSq, angleDiff, doubleEqual, AsmallerB_XoverY
};

================================================
FILE: cv/lsd/src/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
    <title>Line Segment Detector Demo</title>
  </head>
  <body>
    <main>
      <div id="content" />
    </main>
  </body>
</html>

================================================
FILE: cv/lsd/src/lsd.js
================================================
/**
 * Line Segment Detector (LSD) module
 * @author https://github.com/wellflat
 */

import * as funcs from './funcs';
import { Vec4, Point, CoorList, RegionPoint, Rect, Edge } from './types';

/**
 * Create a LineSegmentDetector object.
 * Specifying scale, number of subdivisions for the image,
 * should the lines be refined and other constants as follows:
 *
 * @param refine       How should the lines found be refined?
 *                      REFINE_NONE - No refinement applied.
 *                      REFINE_STD  - Standard refinement is applied. E.g. breaking arches into smaller line approximations.
 *                      REFINE_ADV  - Advanced refinement. Number of false alarms is calculated,
 *                                    lines are refined through increase of precision, decrement in size, etc.
 * @param scale        The scale of the image that will be used to find the lines. Range (0..1].
 * @param sigmaScale   Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale.
 * @param quant        Bound to the quantization error on the gradient norm.
 * @param angTh        Gradient angle tolerance in degrees.
 * @param logEps       Detection threshold: -log10(NFA) > _log_eps
 * @param densityTh    Minimal density of aligned region points in rectangle.
 * @param nBins        Number of bins in pseudo-ordering of gradient modulus.
 */
export default class LSD {
    constructor(
        refineType = funcs.REFINE_NONE, scale = 0.8, sigmaScale = 0.6, quant = 2.0,
        angTh = 22.5, logEps = 0.0, densityTh = 0.7, nBins = 1024
    ) {
        this.refineType = refineType;
        this.scale = scale;
        this.sigmaScale = sigmaScale;
        this.quant = quant;
        this.angTh = angTh;
        this.logEps = logEps;
        this.densityTh = densityTh;
        this.nBins = nBins;
        /** @type {ImageData} */
        this.image = null;
        /** @private @type {Uint8ClampedArray} */
        this.imageData = null;
        /** @type {number} */
        this.width = 0;
        /** @type {number} */
        this.height = 0;
        /** @type {CoorList[]} */
        this.list = [];
        /** @type {Float64Array} */
        this.angles = null;
        /** @type {Float64Array} */
        this.modgrad = null;
        /** @type {Uint8Array} */
        this.used = null; 
    }
    /**
     * Detect lines in the input image.
     * @param {ImageData} image
     * @return {Vec4[]}
     */
    detect(image) {
        this.image = image;
        this.width = image.width;
        this.height = image.height;
        const lines = this.lsd();
        return lines;
    }
    /**
     * Draws the line segments on a given image.
     * @param {CanvasRenderingContext2D} context
     * @param {Vec4[]} lines
     * @param {string} color
     */
    drawSegments(context, lines, color = '#ff0000') {
        context.strokeStyle = color;
        context.lineWidth = 1;
        lines.forEach(v => {
            context.beginPath();
            context.moveTo(v.x1, v.y1);
            context.lineTo(v.x2, v.y2);
            context.stroke();
            context.closePath();
        });
    }

    /**
     * for debug
     * @param {CanvasRenderingContext2D} context 
     */    
    putImageData(context) {
        let src = this.imageData,
            image = context.createImageData(this.width, this.height),
            dst = image.data,
            len = image.data.length;
        for (let i = 0; i < len; i += 4) {
            dst[i] = dst[i + 1] = dst[i + 2] = src[i/4];
            dst[i + 3] = 255;
        }
        context.putImageData(image, 0, 0);
    }
    /**
     * @return {Vec4[]}  Return: A vector of Vec4f elements specifying the beginning and ending point of a line.
     *                   Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
     *                   Returned lines are strictly oriented depending on the gradient.
     */
    lsd() {
        /** @type {Vec4[]} */
        let lines = [];
        const prec = Math.PI * this.angTh / 180;
        const p = this.angTh / 180;
        const rho = this.quant / Math.sin(prec);
        if (this.scale != 1) {
            const sigma = this.scale < 1 ? this.sigmaScale / this.scale : this.sigmaScale;
            const sprec = 3;
            const h = Math.ceil(sigma * Math.sqrt(2 * sprec * Math.log(10.0)));
            const kSize = 1 + 2 * h;
            const reshaped = this.reshape(this.image);
            this.imageData = this.gaussianBlur(reshaped, kSize, sigma);
            this.computeLevelLineAngles(rho, this.nBins);
        } else {
            this.imageData = this.reshape(this.image);
            this.computeLevelLineAngles(rho, this.nBins);
        }

        const LOG_NT = 5 * (Math.log10(this.width) + Math.log10(this.height)) / 2 + Math.log10(11.0);
        const minRegSize = -LOG_NT / Math.log10(p);
        this.used = new Uint8Array(this.imageData.length);
        for (let i = 0, listSize = this.list.length; i < listSize; i++) {
            const point = this.list[i].p;
            if ((this.at(this.used, point) === funcs.NOT_USED) &&
                (this.at(this.angles, point) !== funcs.NOT_DEF)) {
                let regAngle = 0.0;
                /** @type {RegionPoint[]} */
                let reg = [];
                regAngle = this.regionGrow(this.list[i].p, reg, regAngle, prec);
                if (reg.length < minRegSize) {
                    continue;
                }
                let rect = new Rect();
                this.region2Rect(reg, regAngle, prec, p, rect);
                let logNfa = -1;
                if (this.refineType > funcs.REFINE_NONE) {
                    if (!this.refine(reg, regAngle, prec, p, rect, this.densityTh)) {
                        continue;
                    }
                    if (this.refineType >= funcs.REFINE_ADV) {
                        logNfa = this.improveRect(rect);
                        if (logNfa <= this.logEps) {
                            continue;
                        }
                    }
                }
                rect.x1 += 0.5;
                rect.y1 += 0.5;
                rect.x2 += 0.5;
                rect.y2 += 0.5;
                /*
                if (this.scale != 1) {
                    rect.x1 /= this.scale;
                    rect.y1 /= this.scale;
                    rect.x2 /= this.scale;
                    rect.y2 /= this.scale;
                    rect.width /= this.scale;
                }
                */
                lines.push(new Vec4(rect.x1, rect.y1, rect.x2, rect.y2));
            }
        }
        return lines;
    }

    /**
     * @param {number} threshold The minimum value of the angle that is considered defined, otherwise NOTDEF
     * @param {number} nBins     The number of bins with which gradients are ordered by, using bucket sort.
     */
    computeLevelLineAngles(threshold, nBins) {
        const imageData = this.imageData;
        const width = this.width;
        const height = this.height;
        this.angles = new Float64Array(imageData.length);
        this.modgrad = new Float64Array(imageData.length);
        this.angles = this.setRow(this.angles, height - 1, funcs.NOT_DEF);
        this.angles = this.setCol(this.angles, width - 1, funcs.NOT_DEF);
        let maxGrad = -1.0;
        for (let y = 0; y < height - 1; y++) {
            const step = y * width;
            const nextStep = (y + 1) * width;
            for (let x = 0; x < width - 1; x++) {
                const DA = imageData[x + 1 + nextStep] - imageData[x + step];
                const BC = imageData[x + 1 + step] - imageData[x + nextStep];
                const gx = DA + BC;
                const gy = DA - BC;
                const norm = Math.sqrt((gx * gx + gy * gy) / 4.0);
                this.modgrad[x + step] = norm;
                if (norm <= threshold) {
                    this.angles[x + step] = funcs.NOT_DEF;
                } else {
                    this.angles[x + step] = Math.atan2(gx, -gy);
                    if (norm > maxGrad) {
                        maxGrad = norm;
                    }
                }
            }
        }
        /** @type {CoorList[]} */
        let rangeS = [];
        rangeS.length = nBins;
        /** @type {CoorList[]} */
        let rangeE = [];
        rangeE.length = nBins;
        let count = 0;
        const binCoef = (maxGrad > 0) ? (nBins - 1) / maxGrad : 0;
        for (let y = 0; y < height - 1; y++) {
            let step = y * width;
            for (let x = 0; x < width - 1; x++) {
                let i = Math.floor(this.modgrad[x + step] * binCoef);
                if (!rangeE[i]) {
                    this.list[count] = new CoorList();
                    rangeE[i] = rangeS[i] = this.list[count];
                    count++;
                } else {
                    this.list[count] = new CoorList();
                    rangeE[i] = this.list[count];
                    rangeE[i].next = this.list[count];
                    count++;
                }
                rangeE[i].p = new Point(x, y);
                rangeE[i].next = null;
            }
        }
        let idx = nBins - 1;
        for (; idx > 0 && !rangeS[idx]; idx--) {
            // do nothing.
        }
        let start = rangeS[idx];
        let endIdx = idx;
        if (start) {
            while (idx > 0) {
                idx--;
                if (rangeS[idx]) {
                    rangeE[endIdx].next = rangeS[idx];
                    rangeE[endIdx] = rangeE[idx];
                    endIdx = idx;
                }
            }
        }
    }

    /**
     * @param {Point} s
     * @param {RegionPoint[]} reg
     * @param {number} regAngle
     * @param {number} prec
     */
    regionGrow(s, reg, regAngle, prec) {
        let seed = new RegionPoint();
        seed.x = s.x;
        seed.y = s.y;
        seed.used = this.at(this.used, s);
        regAngle = this.at(this.angles, s);
        seed.angle = regAngle;
        seed.modgrad = this.at(this.modgrad, s);
        seed.used = funcs.USED;
        reg.push(seed);
        let sumdx = Math.cos(regAngle);
        let sumdy = Math.sin(regAngle);

        for (let i = 0; i < reg.length; i++) {
            const rpoint = reg[i],
                xxMin = Math.max(rpoint.x - 1, 0),
                xxMax = Math.min(rpoint.x + 1, this.width - 1),
                yyMin = Math.max(rpoint.y - 1, 0),
                yyMax = Math.min(rpoint.y + 1, this.height - 1);
            for (let yy = yyMin; yy <= yyMax; yy++) {
                const step = yy * this.width;
                for (let xx = xxMin; xx <= xxMax; xx++) {
                    let isUsed = this.used[xx + step];
                    if (isUsed != funcs.USED && this.isAligned(xx, yy, regAngle, prec)) {
                        const angle = this.angles[xx + step];
                        isUsed = funcs.USED;
                        this.used[xx + step] = funcs.USED;
                        let regionPoint = new RegionPoint(
                            xx, yy, angle, this.modgrad[xx + step], isUsed
                        );
                        reg.push(regionPoint);
                        sumdx += Math.cos(angle);
                        sumdy += Math.sin(angle);
                        regAngle = Math.atan2(sumdy, sumdx);
                    }
                }
            }
        }
        return regAngle;
    }

    /**
     * @param {number} x
     * @param {number} y
     * @param {number} theta
     * @param {number} prec
     * @return {boolean}
     */
    isAligned(x, y, theta, prec) {
        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
            return false;
        }
        const a = this.angles[x + y * this.width];
        if (a === funcs.NOT_DEF) {
            return false;
        }
        let nTheta = theta - a;
        if (nTheta < 0) {
            nTheta = -nTheta;
        }
        if (nTheta > funcs.M_3_2_PI) {
            nTheta -= funcs.M_2__PI;
            if (nTheta < 0) {
                nTheta = -nTheta;
            }
        }
        return nTheta <= prec;
    }

    /**
     * @param {RegionPoint[]} reg
     * @param {number} regAngle
     * @param {number} prec
     * @param {number} p
     * @param {Rect} rect
     */
    region2Rect(reg, regAngle, prec, p, rect) {
        let x = 0, y = 0, sum = 0;
        for (let i = 0; i < reg.length; i++) {
            const pnt = reg[i];
            const weight = pnt.modgrad;
            x += pnt.x * weight;
            y += pnt.y * weight;
            sum += weight;
        }
        if (sum <= 0) {
            throw new Error('weighted sum must differ from 0');
        }
        x /= sum;
        y /= sum;
        const theta = this.getTheta(reg, x, y, regAngle, prec);
        const dx = Math.cos(theta);
        const dy = Math.sin(theta);
        let lMin = 0, lMax = 0, wMin = 0, wMax = 0;
        for (let i = 0; i < reg.length; i++) {
            let regdx = reg[i].x - x;
            let regdy = reg[i].y - y;
            let l = regdx * dx + regdy * dy;
            let w = -regdx * dy + regdy * dx;
            if (l > lMax) {
                lMax = l;
            } else if (l < lMin) {
                lMin = l;
            }
            if (w > wMax) {
                wMax = w;
            } else if (w < wMin) {
                wMin = w;
            }
        }
        rect.x1 = x + lMin * dx;
        rect.y1 = y + lMin * dy;
        rect.x2 = x + lMax * dx;
        rect.y2 = y + lMax * dy;
        rect.width = wMax - wMin;
        rect.x = x;
        rect.y = y;
        rect.theta = theta;
        rect.dx = dx;
        rect.dy = dy;
        rect.prec = prec;
        rect.p = p;
        if (rect.width < 1.0) {
            rect.width = 1.0;
        }
    }

    /**
     * @param {RegionPoint[]} reg
     * @param {number} x
     * @param {number} y
     * @param {number} regAngle
     * @param {number} prec
     * @return {number}
     */
    getTheta(reg, x, y, regAngle, prec) {
        let ixx = 0.0,
            iyy = 0.0,
            ixy = 0.0;
        for (let i = 0; i < reg.length; i++) {
            const regx = reg[i].x;
            const regy = reg[i].y;
            const weight = reg[i].modgrad;
            let dx = regx - x;
            let dy = regy - y;
            ixx += dy * dy * weight;
            iyy += dx * dx * weight;
            ixy -= dx * dy * weight;
        }
        let check = (funcs.doubleEqual(ixx, 0) && funcs.doubleEqual(iyy, 0) && funcs.doubleEqual(ixy, 0));
        if (check) {
            throw new Error('check if inertia matrix is null');
        }
        let lambda = 0.5 * (ixx + iyy - Math.sqrt((ixx - iyy) * (ixx - iyy) + 4.0 * ixy * ixy));
        let theta = (Math.abs(ixx) > Math.abs(iyy)) ? Math.atan2(lambda - ixx, ixy) :
            Math.atan2(ixy, lambda - iyy);
        if (funcs.angleDiff(theta, regAngle) > prec) {
            theta += Math.PI;
        }
        return theta;
    }

    /**
     * @param {RegionPoint[]} reg
     * @param {number} regAngle
     * @param {number} prec
     * @param {number} p
     * @param {Rect} rect
     * @param {number} densityTh
     * @return {boolean}
     */    
    refine(reg, regAngle, prec, p, rect, densityTh) {
        let density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
        if (density >= densityTh) {
            return true;
        }
        let xc = reg[0].x;
        let yc = reg[0].y;
        const angC = reg[0].angle;
        let sum = 0, sSum = 0, n = 0;
        for (let i = 0; i < reg.length; i++) {
            reg[i].used = funcs.NOT_USED;
            if (funcs.dist(xc, yc, reg[i].x, reg[i].y) < reg.width) {
                const angle = reg[i].angle;
                let angD = funcs.angleDiff(angle, angC);
                sum += angD;
                sSum += angD * angD;
                n++;
            }
            let meanAngle = sum / n;
            let tau = 2.0 * Math.sqrt((sSum - 2.0 * meanAngle * sum) / n + meanAngle * meanAngle);
            this.regionGrow(new Point(reg[0].x, reg[0].y), reg, regAngle, tau);
            if (reg.length < 2) {
                return false;
            }
            this.region2Rect(reg, regAngle, prec, p, rect);
            density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
            if (density < densityTh) {
                return this.reduceRegionRadius(reg, regAngle, prec, p, rect, density, densityTh);
            } else {
                return true;
            }
        }
    }

    /**
     * @param {RegionPoint[]} reg
     * @param {number} regAngle
     * @param {number} prec
     * @param {number} p
     * @param {Rect} rect
     * @param {number} density
     * @param {number} densityTh
     * @return {boolean}
     */    
    reduceRegionRadius(reg, regAngle, prec, p, rect, density, densityTh) {
        let xc = reg[0].x;
        let yc = reg[0].y;
        let radSq1 = funcs.distSq(xc, yc, rect.x1, rect.y1);
        let radSq2 = funcs.distSq(xc, yc, rect.x2, rect.y2);
        let radSq = radSq1 > radSq2 ? radSq1 : radSq2;
        while (density < densityTh) {
            radSq *= 0.75 * 0.75; // reduce region's radius to 75%
            for (let i = 0; i < reg.length; i++) {
                if (funcs.distSq(xc, yc, reg[i].x, reg[i].y) > radSq) {
                    // remove point from the region
                    reg[i].used = funcs.NOT_USED;
                    const tmp = reg[i];
                    reg[i] = reg[reg.length - 1];
                    reg[reg.length - 1] = tmp;
                    reg.pop();
                    --i;
                }
            }
            if (reg.length < 2) {
                return false;
            }
            this.region2Rect(reg, regAngle, prec, p, rect);
            density = reg.length / (funcs.dist(rect.x1, rect.y1, rect.x2, rect.y2) * rect.width);
        }
        return true;
    }

    /**
     * @param {Rect} rect
     * @return {number}
     */    
    improveRect(rect) {
        let delta = 0.5;
        let delta2 = delta / 2.0;
        let logNfa = this.rectNfa(rect);
        if (logNfa > this.logEps) {
            return logNfa;
        }
        let r = new Rect();
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            r.p /= 2;
            r.prec = r.p * Math.PI;
            let logNfaNew = this.rectNfa(rect);
            if (logNfaNew > logNfa) {
                logNfa = logNfaNew;
                rect.copy(r);
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.width -= delta;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.x1 -= -r.dy * delta2;
                r.y1 -= r.dx * delta2;
                r.x2 -= -r.dy * delta2;
                r.y2 -= r.dx * delta2;
                r.width -= delta;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        if (logNfa > this.logEps) {
            return logNfa;
        }
        r.copy(rect);
        for (let n = 0; n < 5; n++) {
            if ((r.width - delta) >= 0.5) {
                r.p /= 2;
                r.prec = r.p * Math.PI;
                let logNfaNew = this.rectNfa(r);
                if (logNfaNew > logNfa) {
                    rect.copy(r);
                    logNfa = logNfaNew;
                }
            }
        }
        return logNfa;
    }

    /**
     * @param {Rect} rect
     * @return {number}
     */    
    rectNfa(rect) {
        let totalPts = 0,
            algPts = 0,
            halfWidth = rect.width / 2.0,
            dyhw = rect.dy * halfWidth,
            dxhw = rect.dx * halfWidth,
            orderedX = [
                new Edge(),
                new Edge(),
                new Edge(),
                new Edge()
            ],
            minY = orderedX[0],
            maxY = orderedX[0];
        orderedX[0].p.x = rect.x1 - dyhw;
        orderedX[0].p.y = rect.y1 + dxhw;
        orderedX[1].p.x = rect.x2 - dyhw;
        orderedX[1].p.y = rect.y2 + dxhw;
        orderedX[2].p.x = rect.x2 + dyhw;
        orderedX[2].p.y = rect.y2 - dxhw;
        orderedX[3].p.x = rect.x1 + dyhw;
        orderedX[3].p.y = rect.y1 - dxhw;

        orderedX.sort(funcs.AsmallerB_XoverY);
        
        for (let i = 1; i < 4; i++) {
            if (minY.p.y > orderedX[i].p.y) {
                minY = orderedX[i];
            }
            if (maxY.p.y < orderedX[i].p.y) {
                maxY = orderedX[i];
            }
        }
        minY.taken = true;
        let leftmost = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!leftmost) {
                    leftmost = orderedX[i];
                } else if (leftmost.p.x > orderedX[i].p.x) {
                    leftmost = orderedX[i];
                }
            }
        }
        leftmost.taken = true;
        let rightmost = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!rightmost) {
                    rightmost = orderedX[i];
                } else if (rightmost.p.x < orderedX[i].p.x) {
                    rightmost = orderedX[i];
                }
            }
        }
        rightmost.taken = true;
        let tailp = null;
        for (let i = 0; i < 4; i++) {
            if (!orderedX[i].taken) {
                if (!tailp) {
                    tailp = orderedX[i];
                } else if (tailp.p.x > orderedX[i].p.x) {
                    tailp = orderedX[i];
                }
            }
        }
        tailp.taken = true;
        let flstep = (minY.p.y != leftmost.p.y) ?
            (minY.p.x + leftmost.p.x) / (minY.p.y - leftmost.p.y) : 0;
        let slstep = (leftmost.p.y != tailp.p.x) ?
            (leftmost.p.x = tailp.p.x) / (leftmost.p.y - tailp.p.x) : 0;
        let frstep = (minY.p.y != rightmost.p.y) ?
            (minY.p.x - rightmost.p.x) / (minY.p.y - rightmost.p.y) : 0;
        let srstep = (rightmost.p.y != tailp.p.x) ?
            (rightmost.p.x - tailp.p.x) / (rightmost.p.y - tailp.p.x) : 0;
        let lstep = flstep, rstep = frstep;
        let leftX = minY.p.x, rightX = minY.p.x;
        let minIter = minY.p.y;
        let maxIter = maxY.p.y;
        for (let y = minIter; y <= maxIter; y++) {
            if (y < 0 || y >= this.height) {
                continue;
            }
            for (let x = leftX; x <= rightX; x++) {
                if (x < 0 || x >= this.width) {
                    continue;
                }
                totalPts++;
                if (this.isAligned(x, y, rect.theta, rect.prec)) {
                    algPts++;
                }
            }
            if (y >= leftmost.p.y) {
                lstep = slstep;
            }
            if (y >= rightmost.p.y) {
                rstep = srstep;
            }
            leftX += lstep;
            rightX += rstep;
        }
        return this.nfa(totalPts, algPts, rect.p);
    }

    /**
     * @param {number} n
     * @param {number} k
     * @param {number} p
     */    
    nfa(n, k, p) {
        const LOG_NT = 5 * (Math.log10(this.width) + Math.log10(this.height)) / 2 + Math.log10(11.0);
        if (n == 0 || k == 0) {
            return -LOG_NT;
        }
        if (n == k) {
            return -LOG_NT - n * Math.log10(p);
        }
        let pTerm = p / (1 - p);
        let log1Term = (n + 1) - funcs.logGamma(k + 1)
            - funcs.logGamma(n - k + 1)
            + k * Math.log(p) + (n - k) * Math.log(1.0 - p);
        let term = Math.exp(log1Term);
        if (funcs.doubleEqual(term, 0)) {
            if (k > n * p) {
                return -log1Term / funcs.M_LN10 - LOG_NT;
            } else {
                return -LOG_NT;
            }
        }
        let binTail = term;
        let tolerance = 0.1;
        for (let i = k + 1; i <= n; i++) {
            let binTerm = (n - i + 1) / i;
            let multTerm = binTerm * pTerm;
            term *= multTerm;
            binTail += term;
            if (binTerm < 1) {
                let err = term * ((1 - Math.pow(multTerm, (n - i + 1))) / (1 - multTerm) - 1);
                if (err < tolerance * Math.abs(-Math.log10(binTail) - LOG_NT) * binTail) {
                    break;
                }
            }
        }
        return -Math.log10(binTail) - LOG_NT;
    }

    /**
     * @param {Uint8ClampedArray} imageData
     * @param {number} kSize
     * @param {number} sigma
     * @return {Uint8ClampedArray}
     */    
    gaussianBlur(imageData, kSize, sigma) {
        let width = this.width,
            height = this.height,
            src = imageData,
            ctx = document.createElement('canvas').getContext('2d'),
            tmp = ctx.createImageData(width, height),
            dst = null,
            kernel = this.getGaussianKernel(kSize, sigma),
            r = (kSize - 1) / 2;
        tmp = this.reshape(tmp);
        dst = new Uint8ClampedArray(tmp.length);
        // separate 2d-filter
        for (let y = 0; y < height; y++) {
            let step = y * width;
            for (let x = 0; x < width; x++) {
                let buff = 0;
                let i = x + step;
                let k = 0;
                for (let kx = -r; kx <= r; kx++) {
                    let px = x + kx;
                    if (px <= 0 || width <= px) {
                        px = x;
                    }
                    let j = px + step;
                    buff += src[j] * kernel[k];
                    k++;
                }
                tmp[i] = buff;
            }
        }
        
        for (let x = 0; x < width; x++) {
            for (let y = 0; y < height; y++) {
                let step = y * width;
                let buff = 0;
                let i = x + step;
                let k = 0;
                for (let ky = -r; ky <= r; ky++) {
                    let py = y + ky;
                    let kStep = ky * width;
                    if (py <= 0 || height <= py) {
                        py = y;
                        kStep = 0;
                    }
                    let j = i + kStep;
                    buff += tmp[j] * kernel[k];
                    k++;
                }
                dst[i] = buff;
            }
        }
        return dst;
    }

    /**
     * @param {number} kSize
     * @param {number} sigma
     * @return {number[]}
     */
    getGaussianKernel(kSize, sigma) {
        // 1d-kernel
        let kernel = [];
        let sigmaX = sigma > 0 ? sigma : ((kSize - 1) * 0.5 - 1) * 0.3 + 0.8;
        let scale2X = -0.5 / (sigmaX * sigmaX);
        let sum = 0.0;
        for (let i = 0; i < kSize; i++) {
            let x = i - (kSize - 1) * 0.5;
            kernel[i] = Math.exp(scale2X * x * x);
            sum += kernel[i];
        }
        sum = 1. / sum;
        for (let i = 0; i < kSize; i++) {
            kernel[i] *= sum;
        }
        return kernel;
    }
    /**
     * @param {ImageData} image
     * @return {Uint8ClampedArray}
     */
    reshape(image) {
        let src = image.data;
        let reshaped = new Uint8ClampedArray(src.length / 4);
        let len = reshaped.length;
        for (let i = 0; i < len; i++) {
            reshaped[i] = src[i * 4];
        }
        return reshaped;
    }

    /**
     * @param {Uint8Array|Float64Array} data
     * @param {Point} p 
     */
    at(data, p) {
        return data[p.x + (p.y * this.width)];
    }

    /**
     * @param {Float64Array} data
     * @param {number} rowIndex
     */
    row(data, rowIndex) {
        let i = rowIndex * this.width; 
        return data.subarray(i, i + this.width);
    }

    /**
     * @param {Float64Array} data
     * @param {number} index
     * @param {number} value
     * @return {null}
     */
    setRow(data, index, value) {
        let from = index * this.width;
        let to = from + this.width;
        for (let i = from; i < to; i++) {
            data[i] = value;
        }
        return data;
    }

    /**
     * @param {Float64Array} data
     * @param {number} index
     * @param {number} value
     * @return {null}
     */
    setCol(data, index, value) {
        let to = this.height * this.width;
        let step = this.width;
        for (let i = index; i < to; i += step) {
            data[i] = value;
        }
        return data;
    }
}

================================================
FILE: cv/lsd/src/lsd_component.js
================================================
import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import LSD from './lsd';

export default class LSDComponent extends React.Component {
    constructor(props) {
        super(props);
        this.onLoad = this.onLoad.bind(this);
    }
    componentDidMount() {
        this.image = new Image();
        this.image.onload = this.onLoad;
        this.image.src = this.props.src;
        this.canvas = this.refs.canvas;
        this.width = 0;
        this.height = 0;
    }
    componentDidUpdate() {
        this.image.src = this.props.src;
    }
    apply(e) {
        e.preventDefault();
        const ctx = this.canvas.getContext('2d'),
            imageData = ctx.getImageData(0, 0, this.width, this.height),
            scale = 0.8,
            detector = new LSD(0, scale),
            lines = detector.detect(imageData);
        console.log('lines: ' + lines.length.toString());
        detector.drawSegments(ctx, lines);
    }
    reset(e) {
        e.preventDefault();
        const ctx = this.canvas.getContext('2d');
        ctx.drawImage(this.image, 0, 0, this.width, this.height);
    }
    onLoad() {
        const ctx = this.canvas.getContext('2d');
        this.width = this.image.width;
        this.height = this.image.height;
        this.canvas.width = this.width;
        this.canvas.height = this.height;
        ctx.drawImage(this.image, 0, 0, this.width, this.height);
    }
    render() {
        return (
            <article>
                <div>
                    <canvas ref="canvas" />
                </div>
                <div>
                    <RaisedButton ref="button" label="detect line segments" primary={true}
                        onTouchTap={e => this.apply(e)} />
                    <RaisedButton ref="reset" label="reset canvas" primary={false}
                        onTouchTap={e => this.reset(e)} />
                </div>
            </article>
        )
    }
}

================================================
FILE: cv/lsd/src/types.js
================================================
class Vec4 {
    constructor(x1 = 0, y1 = 0, x2 = 0, y2 = 0) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }
}

class Point {
    constructor(x = 0.0, y = 0.0) {
        this.x = x;
        this.y = y;
    }
}

class CoorList {
    constructor() {
        this.p = new Point();
        /** @type {CoorList} */
        this.next = null;
    }
}

class RegionPoint {
    constructor(x = 0, y = 0, angle = 0.0, modgrad = 0.0, used = null) {
        this.x = x;
        this.y = y;
        this.angle = angle;
        this.modgrad = modgrad;
        /** @type {number} */
        this.used = used;
    }
}

class Rect {
    constructor(
        x1 = 0, y1 = 0, x2 = 0, y2 = 0,
        width = 0, height = 0, x = 0, y = 0, theta = 0,
        dx = 0, dy = 0, prec = 0, p = 0
    ) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.width = width;
        this.height = height;
        this.x = x;
        this.y = y;
        this.theta = theta;
        this.dx = dx;
        this.dy = dy;
        this.prec = prec;
        this.p = p;
    }
    /**
     * @param {Rect} rect
     */
    copy(rect) {
        this.x1 = rect.x1;
        this.y1 = rect.y1;
        this.x2 = rect.x2;
        this.y2 = rect.y2;
        this.width = rect.width;
        this.height = rect.height;
        this.x = rect.x;
        this.y = rect.y;
        this.theta = rect.theta;
        this.dx = rect.dx;
        this.dy = rect.dy;
        this.prec = rect.prec;
        this.p = rect.p;
    }
}

class Edge {
    constructor() {
        this.p = new Point();
        this.taken = null;
    }
}

export {
    Vec4, Point, CoorList, RegionPoint, Rect, Edge
};

================================================
FILE: cv/lsd/webpack.config.js
================================================
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = {
    entry: __dirname + '/src/app.js',
    output: {
        path: __dirname + '/dst',
        filename: 'bundle.js',
    },
    module: {
        loaders: [
            {
                test: /\.js[x]?$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
                query: {
                    presets: ['es2015', 'react'],//, 'react-hmre']
                }
            },
            {
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
                test: /\.(jpg|png)$/,
                loader: 'url-loader'
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx']
    },
    devServer: {
        contentBase: '/dst',
        port: 8888
    },
    devtool: 'source-map',
    plugins: [
        new HtmlWebpackPlugin({
            title: "React Sample",
            filename: 'index.html',
            template: __dirname + '/src/index.html'
        })    
    ]
};

================================================
FILE: cv/ort_web/HelloONNX.vue
================================================
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <canvas width="32" height="32" ref="canvas"></canvas>
    <button type="button" @click="inference">inference</button>
    <span>{{ infoLabel }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { InferenceSession, Tensor } from 'onnxruntime-web';
interface DataType {
  modelPath: string,
  imagePath: string,
  imageData: ImageData | null,
  ctx: CanvasRenderingContext2D | null,
  session: InferenceSession | null,
  infoLabel: string
}
export default defineComponent({
  name: 'HelloONNX',
  props: {
    msg: String,
  },
  data(): DataType {
    return {
      modelPath: 'cifar10_net.onnx',  // ONNX model file name
      imagePath: require("@/assets/cat9.png"),  // test image
      imageData: null,
      ctx: null,
      session: null,
      infoLabel: ""
    };
  },
  async mounted() {
    const option = {executionProviders: ['wasm', 'webgl']};
    this.session = await InferenceSession.create(this.modelPath, option);
    this.infoLabel = "loading model complete."
    const image = new Image();
    image.src = this.imagePath;
    const isCanvas = (x: any): x is HTMLCanvasElement => x instanceof HTMLCanvasElement;
    image.onload = () => {
      // put image data on the HTML canvas
      const ref = this.$refs;
      if(!isCanvas(ref.canvas)) return;
      this.ctx = ref.canvas.getContext("2d");
      if(this.ctx == null) return;
      const [w, h] = [this.ctx.canvas.width, this.ctx.canvas.height];
      this.ctx.drawImage(image, 0, 0, w, h);
      this.imageData = this.ctx.getImageData(0, 0, w, h);
    };
  },
  methods: {
    async inference(): Promise<void> {
      if(this.session == null || this.imageData == null) return;
      const { data, width, height } = this.imageData;
      // normalize
      const processed = this.normalize((data as Uint8ClampedArray), width, height);
      // run inference using ORT
      const tensor = new Tensor("float32", processed, [1, 3, width, height]);
      const feed = { input: tensor };
      const result = await this.session.run(feed);
      const predicted = this.softmax((result.output.data as Float32Array));
      // view result
      this.infoLabel = this.getClass(predicted).toString();
    },
    normalize(src: Uint8ClampedArray, width: number, height: number): Float32Array {
      const dst = new Float32Array(width * height * 3);
      const transforms = [[0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]];
      const step = width * height;
      for(let y = 0; y < height; y++) {
        for(let x = 0; x < width; x++) {
          const [di, si] = [y * width + x, (y * width + x) * 4];
          // normalize data
          // format RGBARGBARGBA... to RRR...GGG...BBB...
          dst[di] = ((src[si + 0] / 255) - transforms[0][0]) / transforms[1][0];
          dst[di + step] = ((src[si + 1] / 255) - transforms[0][1]) / transforms[1][1];
          dst[di + step * 2] = ((src[si + 2] / 255) - transforms[0][2]) / transforms[1][2];
        }
      }
      return dst;
    },
    softmax(data: Float32Array): Float32Array {
      const max = Math.max(...data);
      const d = data.map(y => Math.exp(y - max)).reduce((a, b) => a + b);
      return data.map((value, index) => Math.exp(value - max) / d);
    },
    getClass(data: Float32Array): [string, number] {
      // CIFAR-10 classes
      const classes = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'];
      const maxProb = Math.max(...data);
      return [classes[data.indexOf(maxProb)], maxProb];
    }
  }
});
</script>

================================================
FILE: cv/ort_web/README.md
================================================
## Image Classification using ONNX Runtime for Web (ORT Web) 

this example is the [CIFAR-10](https://www.cs.toronto.edu/~kriz/cifar.html) classification build by [Vue.js](https://vuejs.org/index.html) component

see also: [ONNX Runtime Web](https://github.com/microsoft/onnxruntime/tree/master/js/web#readme)

================================================
FILE: cv/pixel_clustering/README.md
================================================
# Pixel Clustering Module

## description

Pixel clustering using k-means++ algorithm

see also [blog entry][entry]

### sample
[![pixel_clustering](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/pixel_clustering.jpg)](http://rest-term.com/labs/html5/pixelclustering.html)

(Tests: IE10, Firefox23.0, Chrome28.0, Safari6.0)

## usage

```js
var ctx = document.querySelector('#Canvas').getContext('2d');
// source image, callback function
PixelCluster.load(srcImgName, function() {
  // performs k-means on a set of observation vectors forming k clusters
  var division = 100;
  var k = 4;
  var method = PixelCluster.KMEANS_PP;  // KMEANS_PP or KMEANS_RANDOM
  PixelCluster.perform(division, k, method, function(result) {
    // render the result to canvas element
    PixelCluster.render(ctx, division, result);
  });
});
```

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/3073/


================================================
FILE: cv/pixel_clustering/kmeans.js
================================================
/**
 * provides routines for k-means clustering, generating code books,
 * and quantizing vectors by comparing them with centroids.
 * (specified CanvasPixelArray [[R,G,B],[R,G,B],...])
 */

/* performs k-means on a set of observation vectors forming k clusters */
function kmeans(samples, ncluster, method) {
  var centroids = [],
      previous = [],
      clusters = [],
      code = [],
      len = samples.length,
      eps = 1.0e-8,
      maxIter = 1000,
      iter = 0,
      distance = function(a, b) {
        var dr = a[0] - b[0],
            dg = a[1] - b[1],
            db = a[2] - b[2];
        return dr*dr + dg*dg + db*db;
      },
      nearest = function(sample, centroids) {
        var minIndex = 0,
            minDistance = Number.MAX_VALUE,
            clusterCount = centroids.length;
        for(var k=0; k<clusterCount; k++) {
          var d = distance(centroids[k], sample);
          if(minDistance > d) {
            minDistance = d;
            minIndex = k;
          }
        }
        return [minIndex, minDistance];
      },
      initialize = function(samples, ncluster, method, centroids, clusters) {
        var len = samples.length;
        if(method === 'kmeans_pp') {
          // kmeans++
          var d = [], sumDistance = 0.0, label, k, i,
              r = Math.floor(Math.random()*len);
          centroids[0] = [];
          centroids[0][0] = samples[r][0];
          centroids[0][1] = samples[r][1];
          centroids[0][2] = samples[r][2];
          previous[0] = [0.0, 0.0, 0.0];
          clusters[0] = [];
          for(k=1; k<ncluster; k++) {
            sumDistance = 0.0;
            for(i=0; i<len; i++) {
              d[i] = nearest(samples[i], centroids)[1];
              sumDistance += d[i];
            }
            sumDistance *= Math.random();
            for(i=0; i<len; i++) {
              sumDistance -= d[i];
              if(sumDistance > 0) continue;
              centroids[k] = [];
              centroids[k][0] = samples[i][0];
              centroids[k][1] = samples[i][1];
              centroids[k][2] = samples[i][2];
              break;
            }
            previous[k] = [0.0, 0.0, 0.0];
            clusters[k] = [];
          }
          for(i=0; i<len; i++) {
            label = nearest(samples[i], centroids);
            clusters[label[0]].push(samples[i]);
          }
        } else {
          // random
          for(k=0; k<ncluster; k++) {
            centroids[k] = [Math.random()*255, Math.random()*255, Math.random()*255];
            previous[k] = [0.0, 0.0, 0.0];
            clusters[k] = [];
          }
          for(i=0; i<len; i++) {
            label = Math.floor(Math.random()*k);
            clusters[label].push(samples[i]);
          }
        }
        
      },
      canTerminate = function() {
        var cnt = 0;
        for(var k=0; k<ncluster; k++) {
          if(distance(centroids[k], previous[k]) < eps) cnt++;
        }
        if(cnt === ncluster) return true;
        else return false;
      };
  
  // initializes centroids and clusters
  initialize(samples, ncluster, method, centroids, clusters);
  
  while(!canTerminate() && iter < maxIter) {
    iter++;
    // calculates centroids
    for(var k=0; k<ncluster; k++) {
      if(!clusters[k] || !clusters.length) continue;
      var r = 0.0, g = 0.0, b = 0.0, llen = clusters[k].length;
      for(var i=0; i<llen; i++) {
        r += clusters[k][i][0];
        g += clusters[k][i][1];
        b += clusters[k][i][2];
      }
      previous[k][0] = centroids[k][0];
      previous[k][1] = centroids[k][1];
      previous[k][2] = centroids[k][2];
      centroids[k] = [r/llen, g/llen, b/llen];
    }
    // updates clusters
    clusters = [];
    code = [];
    for(i=0; i<len; i++) {
      var minDistance = Number.MAX_VALUE, currentLabel = -1;
      for(k=0; k<ncluster; k++) {
        var d = distance(centroids[k], samples[i]);
        if(d < minDistance) {
          minDistance = d;
          currentLabel = k;
        }
      }
      if(!clusters[currentLabel]) clusters[currentLabel] = [];
      if(!code[currentLabel]) code[currentLabel] = [];
      clusters[currentLabel].push(samples[i]);
      code[currentLabel].push(i);
    }
  }
  return {"centroids":centroids, "code":code};
}

/* quantizing vectors by comparing them with centroids */
function vq(samples, centroids, code) {
  var clusterCount = centroids.length,
      len = samples.length;
  for(var k=0; k<clusterCount; k++) {
    var ilen = code[k].length;
    for(var i=0; i<ilen; i++) {
      samples[code[k][i]] = centroids[k];
    }
  }
  return samples;
}

/* message handler */
self.addEventListener('message', function(e) {
  var message = e.data;
  var codebook = kmeans(message.samples, message.ncluster, message.method);
  var result = vq(message.samples, codebook["centroids"], codebook["code"]);
  postMessage(result);
}, false);

self.addEventListener('error', function(e) {
  postMessage(e);
}, false);


================================================
FILE: cv/pixel_clustering/pixelcluster.js
================================================
/**
 * Pixel Clustering module
 * http://rest-term.com
 */
(function() {
  var PixelCluster;  // top-level namaspace
  var _root = this;  // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    PixelCluster = exports;   // for CommonJS
  } else {
    PixelCluster = _root.PixelCluster = {};
  }

  var ctx = null,
      image = null,
      imgData = null,
      worker = new Worker('lib/js/kmeans.js');
  
  var core = {
    load: function(fileName, onComplete, onError) {
      ctx = document.createElement('canvas').getContext('2d');
      image = new Image();
      imgData = null;
      image.addEventListener('load', function(e) {
        var img = e.target;
        ctx.canvas.width = img.width;
        ctx.canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        imgData = ctx.getImageData(0, 0, img.width, img.height);
        if(typeof onComplete === 'function') {
          onComplete(imgData, new Date());
        }
      }, false);
      image.addEventListener('error', function() {
        if(typeof onError === 'function') {
          onError();
        }
      }, false);
      image.src = fileName;
    },
    perform: function(division, ncluster, method, onComplete, onError) {
      var features = core.extractFeatures(division);
      if(typeof onComplete === 'undefined') {
        var codebook = core.kmeans(features, ncluster, method);
        var result =  core.vq(features, codebook["centroids"], codebook["code"]);
        return result;
      } else {
        var message = {"samples":features, "ncluster":ncluster, "method":method};
        worker.postMessage(message);
        worker.addEventListener('message', function(e) {
          e.target.removeEventListener('message', arguments.callee);
          if(typeof onComplete === 'function') {
            onComplete(e.data);
          }
        }, false);
        worker.addEventListener('error', function(e) {
          e.target.removeEventListener('error', arguments.callee);
          if(typeof onError === 'function') {
            onError();
          }
        }, false);
        return true;
      }
    },
    /* extracts feature vectors */
    extractFeatures: function(division) {
      var w = imgData.width,
          h = imgData.height,
          data = imgData.data,
          len = w*h*4,
          features = [],
          bins = [0, 0, 0],
          step, kstep, dx, dy, inv, i, j;

      if(w%division != 0 || h%division != 0) {
        throw Error('invalid parameter: division');
      }
      dx = w/division;
      dy = h/division;
      inv = 1/(dx*dy);
      // means of each color, each segment
      for(var y=0; y<division; y++) {
        step = y*dy*w << 2;
        for(var x=0; x<division; x++) {
          i = step + (x*dx << 2);
          bins = [0, 0, 0];
          for(var ky=0; ky<dy; ky++) {
            kstep = i + (ky*w << 2);
            for(var kx=0; kx<dx; kx++) {
              j = kstep + (kx << 2);
              bins[0] += data[j];     // R
              bins[1] += data[j + 1]; // G
              bins[2] += data[j + 2]; // B
            }
          }
          features.push([bins[0]*inv, bins[1]*inv, bins[2]*inv]);
        }
      }
      return features;
    },
    /* performs k-means on a set of observation vectors forming k clusters */
    kmeans: function(samples, ncluster, method) {
      var centroids = [],
          previous = [],
          clusters = [],
          code = [],
          len = samples.length,
          eps = 1.0e-8,
          maxIter = 1000,
          iter = 0,
          distance = function(a, b) {
            var dr = a[0] - b[0],
                dg = a[1] - b[1],
                db = a[2] - b[2];
            return dr*dr + dg*dg + db*db;
          },
          nearest = function(sample, centroids) {
            var minIndex = 0,
                minDistance = Number.MAX_VALUE,
                clusterCount = centroids.length;
            for(var k=0; k<clusterCount; k++) {
              var d = distance(centroids[k], sample);
              if(minDistance > d) {
                minDistance = d;
                minIndex = k;
              }
            }
            return [minIndex, minDistance];
          },
          initialize = function(samples, ncluster, method, centroids, clusters) {
            var len = samples.length;
            if(method === 'kmeans_pp') {
              // kmeans++
              var d = [], sumDistance = 0.0, label, k, i,
                  r = Math.floor(Math.random()*len);
              centroids[0] = [];
              centroids[0][0] = samples[r][0];
              centroids[0][1] = samples[r][1];
              centroids[0][2] = samples[r][2];
              previous[0] = [0.0, 0.0, 0.0];
              clusters[0] = [];
              for(k=1; k<ncluster; k++) {
                sumDistance = 0.0;
                for(i=0; i<len; i++) {
                  d[i] = nearest(samples[i], centroids)[1];
                  sumDistance += d[i];
                }
                sumDistance *= Math.random();
                for(i=0; i<len; i++) {
                  sumDistance -= d[i];
                  if(sumDistance > 0) continue;
                  centroids[k] = [];
                  centroids[k][0] = samples[i][0];
                  centroids[k][1] = samples[i][1];
                  centroids[k][2] = samples[i][2];
                  break;
                }
                previous[k] = [0.0, 0.0, 0.0];
                clusters[k] = [];
              }
              for(i=0; i<len; i++) {
                label = nearest(samples[i], centroids);
                clusters[label[0]].push(samples[i]);
              }
            } else {
              // random
              for(k=0; k<ncluster; k++) {
                centroids[k] = [Math.random()*255, Math.random()*255, Math.random()*255];
                previous[k] = [0.0, 0.0, 0.0];
                clusters[k] = [];
              }
              for(i=0; i<len; i++) {
                label = Math.floor(Math.random()*k);
                clusters[label].push(samples[i]);
              }
            }
            
          },
          canTerminate = function() {
            var cnt = 0;
            for(var k=0; k<ncluster; k++) {
              if(distance(centroids[k], previous[k]) < eps) cnt++;
            }
            if(cnt === ncluster) return true;
            else return false;
          },
          sumDistance = function(centroids) {
            var sum = 0.0, len = centroids.length;
            for(var i=0; i<len-1; i++) {
              sum += distance(centroids[i], centroids[i + 1]);
            }
            return sum;
          };
      // initializes centroids and clusters
      initialize(samples, ncluster, method, centroids, clusters);
      
      while(!canTerminate() && iter < maxIter) {
        iter++;
        // calculates centroids
        for(var k=0; k<ncluster; k++) {
          if(!clusters[k] || !clusters.length) continue;
          var r = 0.0, g = 0.0, b = 0.0, llen = clusters[k].length;
          for(var i=0; i<llen; i++) {
            r += clusters[k][i][0];
            g += clusters[k][i][1];
            b += clusters[k][i][2];
          }
          previous[k][0] = centroids[k][0];
          previous[k][1] = centroids[k][1];
          previous[k][2] = centroids[k][2];
          centroids[k] = [r/llen, g/llen, b/llen];
        }
        // updates clusters
        clusters = [];
        code = [];
        for(i=0; i<len; i++) {
          var minDistance = Number.MAX_VALUE, currentLabel = -1;
          for(k=0; k<ncluster; k++) {
            var d = distance(centroids[k], samples[i]);
            if(d < minDistance) {
              minDistance = d;
              currentLabel = k;
            }
          }
          if(!clusters[currentLabel]) clusters[currentLabel] = [];
          if(!code[currentLabel]) code[currentLabel] = [];
          clusters[currentLabel].push(samples[i]);
          code[currentLabel].push(i);
        }
      }
      return {"centroids":centroids, "code":code};
    },
    /* quantizing vectors by comparing them with centroids */
    vq: function(samples, centroids, code) {
      var ncluster = centroids.length,
          len = samples.length;
      for(var k=0; k<ncluster; k++) {
        var ilen = code[k].length;
        for(var i=0; i<ilen; i++) {
          samples[code[k][i]] = centroids[k];
        }
      }
      return samples;
    },
    render: function(context, division, features) {
      var w = imgData.width,
          h = imgData.height,
          data = imgData.data,
          dstImgData = context.getImageData(0, 0, w, h),
          dstData = dstImgData.data,
          len = w*h*4,
          step, kstep, dx, dy, inv, i, j;
      if(w%division != 0 || h%division != 0) {
        throw Error('invalid parameter: division');
      }
      dx = w/division;
      dy = h/division;
      inv = 1/(dx*dy);
      // means of each color, each segment
      var f = 0, p = [];
      for(var y=0; y<division; y++) {
        step = y*dy*w << 2;
        for(var x=0; x<division; x++) {
          i = step + (x*dx << 2);
          p = features[f++];
          for(var ky=0; ky<dy; ky++) {
            kstep = i + (ky*w << 2);
            for(var kx=0; kx<dx; kx++) {
              j = kstep + (kx << 2);
              dstData[j] = p[0];
              dstData[j + 1] = p[1];
              dstData[j + 2] = p[2];
              dstData[j + 3] = 255;
            }
          }
        }
      }
      context.putImageData(dstImgData, 0, 0);
    }
  };
  // public APIs
  PixelCluster.load = core.load;
  PixelCluster.mosaic = core.extractFeatures;
  PixelCluster.perform = core.perform; // using web workers
  PixelCluster.render = core.render;
  PixelCluster.KMEANS_PP = "kmeans_pp";
  PixelCluster.KMEANS_RANDOM = "kmeans_random";
}).call(this);


================================================
FILE: cv/poisson_blending/README.md
================================================
# Poisson Image Editing Module

## description

Image composition using Poisson Image Editing algorithm

see also [blog entry][entry]

### sample
[![poisson_blending](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/poisson_blending.jpg)](http://rest-term.com/labs/html5/poisson.html)

(Tests: IE10, Firefox22.0, Chrome28.0, Safari6.0)

## usage

```js
var ctx = document.querySelector('#Canvas').getContext('2d');
// source image, destination image, mask image, callback function
Poisson.load(srcImgName, dstImgName, maskImgName, function() {
  // max iteration, X offset, Y offset
  var result = Poisson.blend(100, 10, -20);
  // render to canvas
  ctx.putImageData(result, 0, 0);
});
```

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/3066/


================================================
FILE: cv/poisson_blending/poisson.js
================================================
/**
 * Poisson Image Editing module
 * http://rest-term.com
 */
(function() {
  var Poisson;       // top-level namaspace
  var _root = this;  // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    Poisson = exports;   // for CommonJS
  } else {
    Poisson = _root.Poisson = {};
  }

  // core operations
  var EPS = 1.0E-08;
  var ctx = null,
      images = [new Image(), new Image(), new Image()],
      files = [],
      data = [],
      loadedCount = 0;
  var core = {
    // loads images
    load: function(srcImgName, dstImgName, maskImgName, onComplete, onError) {
      ctx = document.createElement('canvas').getContext('2d');
      images[0].src = files[0] = srcImgName;
      images[1].src = files[1] = dstImgName;
      images[2].src = files[2] = maskImgName;
      // load complete handler
      for (var i=0; i<3; i++) {
        var image = images[i];
        image.addEventListener('load', function(e) {
          var img = e.target;
          ctx.canvas.width = img.width;
          ctx.canvas.height = img.height;
          ctx.drawImage(img, 0, 0);
          var imgData = ctx.getImageData(0, 0, img.width, img.height);
          switch(img.src) {
          case files[0]:  // cannot use a 'i' index
            data[0] = imgData;
            break;
          case files[1]:
            data[1] = imgData;
            break;
          case files[2]:
            data[2] = imgData;
            break;
          }
          loadedCount++;
          if(loadedCount === 3) {
            ctx.drawImage(images[1], 0, 0);
            data[3] = ctx.getImageData(0, 0, img.width, img.height);
            if(typeof onComplete === 'function') {
              onComplete(data);
            }
          }
        }, false);
        image.addEventListener('error', function() {
          if(typeof onError === 'function') {
            onError();
          }
        }, false);
      }
    },
    reset: function() {
      ctx.drawImage(images[1], 0, 0);
      data[3] = ctx.getImageData(0, 0, images[1].width, images[1].height);
      return data[3];
    },
    // applies poisson image editing
    blend: function(iteration, offsetX, offsetY) {
      var w = data[0].width,
          h = data[0].height,
          len = w*h*4,
          srcData = data[0].data,
          dstData = data[1].data,
          maskData = data[2].data,
          blendData = data[3].data,
          edge = false,
          error = 0.0,
          sumf = [0.0, 0.0, 0.0],
          sumfstar = [0.0, 0.0, 0.0],
          sumvq = [0.0, 0.0, 0.0],
          fp = [],
          fq =  [],
          gp = [],
          gq = [],
          subf = [],
          subg = [],
          naddr = [],
          threashold = 128,
          terminate = [],
          step, l, m;
      // validation
      if(!(parseInt(iteration) && parseInt(offsetX) && parseInt(offsetY))) {
        throw TypeError('invalid parameter type');
      }
      // core operation
      for(var i=0; i<iteration; i++) {
        terminate = [true, true, true];
        for(var y=1; y<h-1; y++) {
          step = y*w << 2;
          for(var x=1; x<w-1; x++) {
            l = step + (x << 2);
            m = offsetY*w + offsetX << 2;
            naddr = [l - (w << 2), l - 4, l + 4, l + (w << 2)];
            if(maskData[l] > threashold) { // on the mask
              sumf = [0.0, 0.0, 0.0];
              sumfstar = [0.0, 0.0, 0.0];
              sumvq = [0.0, 0.0, 0.0];
              edge = false;
              for(var n=0; n<4; n++) {
                if(maskData[naddr[n]] <= threashold) {
                  edge = true;
                  break;
                }
              }
              if(!edge) {
                if(y + offsetY >= 0 && x + offsetX >= 0 &&
                   y + offsetY < h && x + offsetX < w) {
                  for(n=0; n<4; n++) {
                    for(var c=0; c<3; c++) {
                      sumf[c] += blendData[naddr[n] + m + c];
                      sumvq[c] += srcData[l + c] - srcData[naddr[n] + c];
                    }
                  }
                }
              } else {
                if(y + offsetY >= 0 && x + offsetX >= 0 &&
                   y + offsetY < h && x + offsetX < w) {
                  fp[0] = dstData[l + m];
                  fp[1] = dstData[l + m + 1];
                  fp[2] = dstData[l + m + 2];
                  gp[0] = srcData[l];
                  gp[1] = srcData[l + 1];
                  gp[2] = srcData[l + 2];
                  for(n=0; n<4; n++) {
                    for(c=0; c<3; c++) {
                      fq[c] = dstData[naddr[n] + m + c];
                      gq[c] = srcData[naddr[n] + c];
                      sumfstar[c] += fq[c];
                      subf[c] = fp[c] - fq[c];
                      subf[c] = subf[c] > 0 ? subf[c] : -subf[c];
                      subg[c] = gp[c] - gq[c];
                      subg[c] = subg[c] > 0 ? subg[c] : -subg[c];
                      if(subf[c] > subg[c]) {
                        sumvq[c] += subf[c];
                      } else {
                        sumvq[c] += subg[c];
                      }
                    }
                  }
                }
              }
              for(c=0; c<3; c++) {
                fp[c] = (sumf[c] + sumfstar[c] + sumvq[c])*0.25; // division 4
                error = Math.floor(fp[c] - blendData[l + m + c]);
                error = error > 0 ? error : -error;
                if(terminate[c] && error > EPS*(1 + (fp[c] > 0 ? fp[c] : -fp[c]))) {
                  terminate[c] = false;
                }
                blendData[l + m + c] = fp[c];
              }
            } // end mask
          } // end x loop
        } // end y loop
        if(terminate[0] && terminate[1] && terminate[2]) break;
      } // end iteration
      return data[3];
    }
  };
  // aliases (public APIs)
  Poisson.load = core.load;
  Poisson.reset = core.reset;
  Poisson.blend = core.blend;
}).call(this);


================================================
FILE: cv/stereo_matching/README.md
================================================
# Stereo Matching Module

## description

computes the disparity map using naive block matching

see also [blog entry][entry]

### sample
[![stereo_matching](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/stereo_matching.jpg)](http://rest-term.com/labs/html5/stereo.html)

(Tests: IE10, Firefox7.0, Chrome14.0, Opera11.51)

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/2940/


================================================
FILE: cv/stereo_matching/stereo-core.js
================================================
/**
 *  computes the disparity for the rectified stereo pair,
 *  naive implementation without using dynamic programming.
 */
function findStereoCorrespondence(pair, state) {
  var w = pair[0].width,
      h = pair[0].height,
      data = [pair[0].data, pair[1].data],
      disparity = [],
      step = w << 2,
      winSize = state.SADWindowSize,
      threshold = state.textureThreshold,
      minDisparity = state.minDisparity,
      maxDisparity = state.numberOfDisparities - minDisparity,
      maxDiff = 255 * winSize * winSize,
      localMin = maxDiff,
      sad = 0,
      diff, cur, ptr;
  for(var y=0, cur=step; y<h-1; y++, cur+=step) {
    for(var x=0, i=cur; x<w; x++, i+=4) {
      for(var d=minDisparity, ptr=i; d<maxDisparity; d++, ptr-=4) {
        if(ptr < cur) continue;
        for(var ly=0; ly<winSize; ly++) {
          if(sad > threshold || y + ly > h) break;
          for(var lx=0, j=ly*step; lx<winSize; lx++, j+=4) {
            if(x + lx > w) break;
            diff = data[0][i + j] - data[1][ptr + j];
            if(isNaN(diff)) diff = 0;
            sad += (diff < 0 ? -diff : diff);
          }
        }
        if(localMin > sad) {
          localMin = sad;
          disparity[i] = disparity[i + 1] = disparity[i + 2] = d << 4;
          disparity[i + 3] = 255;
        }
        sad = 0;
      }
      localMin = maxDiff;
    }
  }
  return {'width':w, 'height':h, 'disparity':disparity};
}

/* message handler */
self.addEventListener('message', function(e) {
  var message = e.data,
      data = message.pair,  // CanvasPixelArray pair
      state = message.state;
  postMessage(findStereoCorrespondence(data, state));
}, false);
self.addEventListener('error', function(e) {
  postMessage(e);
}, false);


================================================
FILE: cv/stereo_matching/stereo.js
================================================
/**
 * Stereo Matching module using Web Workers
 */
(function() {
  var Stereo;        // top-level namespace
  var _root = this;  // reference to 'window' or 'global'

  if(typeof exports !== 'undefined') {
    Stereo = exports;  // for CommonJS
  } else {
    Stereo = _root.Stereo = {};
  }

  var version = {
    release: '0.1.0',
    date: '2011-01'
  };
  Stereo.toString = function() {
    return "version " + version.release + ", released " + version.date;
  };

  // core operations
  var ctx = null,
      left = new Image(),
      right = new Image(),
      data = [null, null],
      state = {},
      worker = new Worker('lib/js/stereo-core.js');
  var core = {
    /* load stereo pair images */
    _load : function(leftSource, rightSource) {
      ctx = document.createElement('canvas').getContext('2d');
      left.src = leftSource;
      right.src = rightSource;
      // load complete handler
      left.addEventListener('load', function() {
        ctx.canvas.width = left.width;
        ctx.canvas.height = left.height;
        ctx.drawImage(left, 0, 0);
        data[0] = ctx.getImageData(0, 0, left.width, left.height);
      }, false);
      right.addEventListener('load', function() {
        ctx.canvas.width = right.width;
        ctx.canvas.height = right.height;
        ctx.drawImage(right, 0, 0);
        data[1] = ctx.getImageData(0, 0, right.width, right.height);
      }, false);
      // load error handler
      left.addEventListener('error', function() {
        alert('can\'t load left image');
      }, false);
      right.addEventListener('error', function() {
        alert('can\'t load right image');
      }, false);
    },
    /* draw disparity map on the canvas */
    _draw : function(data, context) {
      var img = context.getImageData(0, 0, data.width, data.height),
          pixels = img.data,
          disparity = data.disparity,
          len = disparity.length;
      for(var i=0; i<len; i++) {
        pixels[i] = disparity[i];
      }
      context.putImageData(img, 0, 0);
    },
    /* find stereo correspondence using worker */
    _find : function(preset, wSize, nDisparities) {
      core._validate();
      core._createState(preset);
      if(wSize) state.SADWindowSize = wSize;
      if(nDisparities) state.numberOfDisparities = nDisparities;
      var message = {'pair':data, 'state':state};
      worker.postMessage(message);
      return worker;
    },
    /* triangulation */
    _triangulate : function() {
      // TODO
    },
    /* create the structure for block matching algorithm */
    _createState : function(preset) {
      switch(preset.toUpperCase()) {
      case 'BASIC':
      case 'FISH_EYE':
      case 'NARROW':
        // not using currently
      default:
        state.minDisparity = 0;
        state.numberOfDisparities = 10;
        state.SADWindowSize = 5;
        state.textureThreshold = 1500;
        break;
      }
    },
    /* validate stereo pair images */
    _validate : function() {
      if(!left.complete || !right.complete) {
        throw new Error('load images incomplete');
      }
      if(left.width != right.width &&
         left.height != right.height) {
        throw new Error('invalid images, required stereo pair');
      }
    },
    /* cache disparity map data */
    _fetchData : function(key) {
      return JSON.parse(window.localStorage[key]);
    },
    _storeData : function(key, value) {
      window.localStorage[key] = JSON.stringify(value);
    }
  };
  // aliases (public APIs)
  var apis = ['load', 'find', 'draw', 'fetchData', 'storeData'];
  for(var i=0; i<apis.length; i++) {
    Stereo[apis[i]] = core['_' + apis[i]];
  }
}).call(this);

================================================
FILE: cv/utils/histogram.js
================================================
/**
 * Image Histogram Caluculator using Web Worker API
 */
var Class = {
  create : function() {
    var properties = arguments[0];
    function self() {
      this.initialize.apply(this, arguments);
    }
    for(var i in properties) {
      self.prototype[i] = properties[i];
    }
    if(!self.prototype.initialize) {
      self.prototype.initialize = function() {};
    }
    return self;
  }
};

var Histogram = Class.create({
  initialize : function(imageData, type) {
    this.width = imageData.width;
    this.height = imageData.height;
    this.data = imageData.data;
    this.bins = {v1:[], v2:[], v3:[]};
    this.type = type || 'rgb';
    this.fillBins(256, 0);
  },
  fillBins : function(length, value) {
    for(var i=0; i<length; i++) {
      this.bins.v1[i] = value;
      this.bins.v2[i] = value;
      this.bins.v3[i] = value;
    }
  },
  calculate : function() {
    this.convertColor(this.type);
    var len = this.data.length;
    for(var i=0; i<len; i+=4) {
      this.bins.v1[this.data[i]]++;
      this.bins.v2[this.data[i + 1]]++;
      this.bins.v3[this.data[i + 2]]++;
    }
  },
  getMax : function() {
    var max = 0;
    for(var ch in this.bins) {
      for(var i=0; i<256; i++) {
        max = this.bins[ch][i] > max ? this.bins[ch][i] : max;
      }
    }
    return max;
  },
  normalize : function(factor) {
    for(var ch in this.bins) {
      for(var i=0; i<256; i++) {
        this.bins[ch][i] /= factor;
      }
    }
  },
  backProject : function() {
    // TODO
  },
  compare : function(hist, method) {
    // TODO
    switch(method) {
    case 'correl':
      break;
    case 'chisqr':
      break;
    case 'intersect':
      break;
    case 'bhattacharyya':
      break;
    default:
      break;
    }
  },
  convertColor : function(type) {
    // TODO
    switch(type) {
    case 'rgb':
      break;
    case 'gray':
      break;
    case 'hsv':
      break;
    default:
      break;
    }
  }
});

self.addEventListener('message', function(e) {
  var hist = new Histogram(e.data);
  hist.calculate();
  hist.bins.max = hist.getMax();
  postMessage(hist.bins);
}, false);

self.addEventListener('error', function(e) {
  postMessage(e);
}, false);

================================================
FILE: draw/README.md
================================================
# 3D Shapes Drawing

## description

Drawing 3D shapes (pseudo 3D)

[![3d_drawing](https://raw.github.com/wiki/wellflat/imageprocessing-labs/images/3dshape_drawing.png)](http://rest-term.com/labs/html5/)

### demo
[Heart Surface][Heart]

[Mobius Strip][Mobius]

[Klein Bottle][Klein]

(Tests: IE10, Firefox8.0, Safari5.0, Chrome16.0, Opera11.60)

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[Heart]: http://rest-term.com/labs/html5/heart.html
[Mobius]: http://rest-term.com/labs/html5/mobius.html
[Klein]: http://rest-term.com/labs/html5/klein.html
[MIT]: http://www.opensource.org/licenses/mit-license.php
[entry]: http://rest-term.com/archives/2986/


================================================
FILE: draw/heart.js
================================================
/**
 * Heart Surface Maker
 */
var Heart = (function() {
  var _context = null,
      _width = null,
      _height = null,
      _scale = 25,
      _fov = 250,
      _points = [],
      _numPoints = 0,
      _isPlay = false,
      _timerID = null,
      // public methods
      _init = function(context, n) {
        _context = context;
        _width = context.canvas.width;
        _height = context.canvas.height;
        _points = [];
        _setStyle(_context.createLinearGradient(0, 0, 0, 300));
        _setPoints(n);
      },
      _play = function(t, angle) {
        if(!_isPlay) {
          _timerID = setInterval(function() {
            _render(angle)
          }, t);
          _isPlay = true;
        }
      },
      _stop = function() {
        if(_isPlay) {
          clearInterval(_timerID);
          _isPlay = false;
        }
      },
      // private methods
      _setStyle = function(grad) {
        grad.addColorStop(0, 'rgb(255, 255, 255)');
        grad.addColorStop(0.7, 'rgb(196, 196, 196)');
        grad.addColorStop(0.8, 'rgb(160, 160, 160)');
        grad.addColorStop(0.9, 'rgb(128, 128, 128)');
        grad.addColorStop(1, 'rgb(96, 96, 96)');
        _context.fillStyle = grad;
        _context.strokeStyle = 'rgb(255, 0, 160)';
        _context.fillRect(0, 0, _width, _height);
      },
      _setPoints = function(num) {
        var r, theta, z, n = 0, point;
        for(var i=-Math.PI*num; i<=Math.PI*num; i++) {
          for(var j=-num; j<=num; j++) {
            theta = i/num; z = j/num;
            r = 4*Math.sqrt(1 - z*z)*Math.pow(Math.sin(Math.abs(theta)), Math.abs(theta));
            point = [_scale*r*Math.sin(theta),
                     _scale*r*Math.cos(theta),
                     _scale*z];
            _points.push(point);
            n++;
          }
        }
        _numPoints = n;
      },
      _render = function(angle) {
        _context.fillRect(0, 0, _width, _height);
        for(var i=0; i<_numPoints; i++)	{
          _rotateY(_points[i], angle);
          _draw(_points[i]);
        }
      },
      _draw = function(point3d) {
        var scale = _fov/(_fov + point3d[2]),
            x = (point3d[0]*scale) + (_width >> 1),
            y = (point3d[1]*scale) + (_height >> 1);
        _context.lineWidth= scale << 1;
        _context.beginPath();
        _context.moveTo(x, y);
        _context.lineTo(x + scale, y);
        _context.stroke();
      },
      _rotateY = function(point3d, angle) {
        var x = point3d[0],
            z = point3d[2],
            c = Math.cos(angle),
            s = Math.sin(angle),
            tz = z,
            tx = x;
        x = tx*c + tz*s;
        z = tz*c - tx*s;
        point3d[0] = x;
        point3d[2] = z;
      };
  // public APIs
  return {
    init: _init,
    play: _play,
    stop: _stop,
  };
})();

================================================
FILE: draw/klein.js
================================================
/**
 * Klein's Bottle Maker
 */
var KleinBottle = (function() {
  var _context = null,
      _width = null,
      _height = null,
      _scale = 6,
      _fov = 250,
      _points = [],
      _numPoints = 0,
      _isPlay = false,
      _timerID = null,
      // public methods
      _init = function(context, n) {
        _context = context;
        _width = context.canvas.width;
        _height = context.canvas.height;
        _points = [];
        _setStyle(context.createLinearGradient(0, 0, 0, 300));
        _setPoints(n);
      },
      _play = function(t, angle) {
        if(!_isPlay) {
          _timerID = setInterval(function() {
            _render(angle)
          }, t);
          _isPlay = true;
        }
      },
      _stop = function() {
        if(_isPlay) {
          clearInterval(_timerID);
          _isPlay = false;
        }
      },
      // private methods
      _setStyle = function(grad) {
        grad.addColorStop(0, 'rgb(0, 0, 0)');
        grad.addColorStop(0.7, 'rgb(16, 16, 16)');
        grad.addColorStop(0.8, 'rgb(32, 32, 32)');
        grad.addColorStop(0.9, 'rgb(48, 48, 48)');
        grad.addColorStop(1, 'rgb(64, 64, 64)');
        _context.fillStyle = grad;
        _context.strokeStyle = 'rgb(0, 128, 255)';
        _context.fillRect(0, 0, _width, _height);
      },
      _setPoints = function(num) {
        var x, y, u, v, r, n = 0, point;
        for(var i=0; i<=2*Math.PI*num; i++) {
          for(var j=0; j<=2*Math.PI*4.8; j++) {
            u = i/num; v = j/4.8;
            r = 4*(1 - Math.cos(u)/2);
            if(u<Math.PI) {
              x = 6*Math.cos(u)*(1 + Math.sin(u)) + r*Math.cos(u)*Math.cos(v);
              y = 16*Math.sin(u) + r*Math.sin(u)*Math.cos(v);
            } else {
              x = 6*Math.cos(u)*(1 + Math.sin(u)) + r*Math.cos(v + Math.PI);
              y = 16*Math.sin(u);
            }
            point = [_scale*x, _scale*y, _scale*r*Math.sin(v)];
            _points.push(point);
            n++;
          }
        }
        _numPoints = n;
      },
      _render = function(angle) {
        _context.fillRect(0, 0, _width, _height);
        for(var i=0; i<_numPoints; i++)	{
          _rotateX(_points[i], angle);
          _rotateY(_points[i], angle);
          _rotateZ(_points[i], angle);
          _draw(_points[i]);
        }
      },
      _draw = function(point3d) {
        var scale = _fov/(_fov + point3d[2]),
            x = (point3d[0]*scale) + (_width >> 1),
            y = (point3d[1]*scale) + (_height >> 1);
        _context.lineWidth= scale << 1;
        _context.beginPath();
        _context.moveTo(x, y);
        _context.lineTo(x + scale, y);
        _context.stroke();
      },
      _rotateX = function(point3d, angle) {
        var y = point3d[1],
            z = point3d[2],
            c = Math.cos(angle),
            s = Math.sin(angle),
            ty = y,
            tz = z;
        y = ty*c - tz*s;
        z = ty*s + tz*c;
        point3d[1] = y;
        point3d[2] = z;
      },
      _rotateY = function(point3d, angle) {
        var x = point3d[0],
            z = point3d[2],
            c = Math.cos(angle),
            s = Math.sin(angle),
            tz = z,
            tx = x;
        x = tx*c + tz*s;
        z = tz*c - tx*s;
        point3d[0] = x;
        point3d[2] = z;
      },
      _rotateZ = function(point3d, angle) {
        var x = point3d[0],
            y = point3d[1],
            c = Math.cos(angle),
            s = Math.sin(angle),
            tx = x,
            ty = y;
        x = tx*c - ty*s;
        y = tx*s + ty*c;
        point3d[0] = x;
        point3d[1] = y;
      };
  // public APIs
  return {
    init: _init,
    play: _play,
    stop: _stop,
  };
})();

================================================
FILE: draw/lib3d.js
================================================
/**
 * My 3D Library v.0.0.2
 * 
 */
var Class = {
  create : function() {
    var properties = arguments[0];
    function self() {
      this.initialize.apply(this, arguments);
    }
    for(var i in properties) {
      self.prototype[i] = properties[i];
    }
    if(!self.prototype.initialize) {
      self.prototype.initialize = function() {};
    }
    return self;
  }
};

var Point = Class.create({
  initialize : function(x, y) {
    this.x = x || 0.0;
    this.y = y || 0.0;
  }
});

var Vertex3D = Class.create({
  initialize : function(x, y, z) {
    this.x = x || 0.0;
    this.y = y || 0.0;
    this.z = z || 0.0;
    this.length = Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
  },
  clone : function() {
    return new Vertex3D(this.x, this.y, this.z);
  },
  add : function(v) {
    return new Vertex3D(this.x + v.x, this.y + v.y, this.z + v.z);
  },
  sub : function(v) {
    return new Vertex3D(this.x - v.x, this.y - v.y, this.z - v.z);
  },
  dot : function(v) {
    return this.x*v.x + this.y*v.y + this.z*v.z;
  },
  cross : function(v) {
    return new Vertex3D(v.y*this.z - v.z * this.y,
                        v.z*this.x - v.x*this.z,
                        v.x*this.y - v.y*this.x);
  },
  negate : function() {
    this.x *= -1;
    this.y *= -1;
    this.z *= -1;
  },
  normalize : function() {
    if(this.length != 0 && this.length != 1) {
      var mod = 1/this.length;
      this.x *= mod;
      this.y *= mod;
      this.z *= mod;
    }
  },
  project : function(screen) {
    var scale = screen.focalLength/(screen.focalLength + this.z);
    return new Point(
      this.x*scale + screen.projectionCenter.x,
      -this.y*scale + screen.projectionCenter.y
    );
  },
  scaleBy : function(s) {
    this.x *= s;
    this.y *= s;
    this.z *= s;
  },
  rotateX : function(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    return new Vertex3D(
      this.x,
      c*this.y - s*this.z,
      s*this.y + c*this.z
    );
  },
  rotateY : function(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    return new Vertex3D(
      s*this.z + c*this.x,
      this.y,
      c*this.z - s*this.x
    );
  },
  rotateZ : function(angle) {
    var s = Math.sin(angle);
    var c = Math.cos(angle);
    return new Vertex3D(
      c*this.x - s*this.y,
      s*this.x + c*this.y,
      this.z
    );
  }
});

var TriangleMesh3D = Class.create({
  initialize : function(material, vertices, faces) {
    this.material = material;
    if(vertices && vertices.length == 3) {
      this.v0 = vertices[0];
      this.v1 = vertices[1];
      this.v2 = vertices[2];
    }else {
      this.v0 = new Vertex3D(1, 0, 0);
      this.v1 = new Vertex3D(0, 1, 0);
      this.v2 = new Vertex3D(0, 0, 1); 
    }
    this.faces = faces || [];
  },
  draw : function(screen) {
    this.material.drawTriangle(this, screen);
  },
  rotateX : function(angle) {
    this.v0 = this.v0.rotateX(angle);
    this.v1 = this.v1.rotateX(angle);
    this.v2 = this.v2.rotateX(angle);
  },
  rotateY : function(angle) {
    this.v0 = this.v0.rotateY(angle);
    this.v1 = this.v1.rotateY(angle);
    this.v2 = this.v2.rotateY(angle);
  },
  rotateZ : function(angle) {
    this.v0 = this.v0.rotateZ(angle);
    this.v1 = this.v1.rotateZ(angle);
    this.v2 = this.v2.rotateZ(angle);
  },
  translate : function(v) {
    this.v0 = this.v0.add(v);
    this.v1 = this.v1.add(v);
    this.v2 = this.v2.add(v);
  }
});

var Quaternion = Class.create({
  initialize : function(x, y, z, w) {
    this.x = x || 0.0;
    this.y = y || 0.0;
    this.z = z || 0.0;
    this.w = w || 1.0;
    this.EPSILON = 0.000001;
    this.DEGTORAD = Math.PI/180.0;
    this.RADTODEG = 180.0/Math.PI;
  },
  clone : function() {
    return new Quaternion(this.x, this.y, this.z, this.w);
  },
  calculateMultiply : function(a, b) {
    this.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
    this.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
    this.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
    this.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
  },
  setFromAxisAngle : function(x, y, z, angle) {
    var s = Math.sin(angle*0.5);
    var c = Math.cos(angle*0.5);
    this.x = x*s;
    this.y = y*s;
    this.z = z*s;
    this.w = c;
    this.normalize();
  },
  setFromEuler : function(ax, ay, az, useDegrees) {
    if(useDegrees) {
      ax *= DEGTORAD;
      ay *= DEGTORAD;
      az *= DEGTORAD;
    }
    var fSinPitch = Math.sin(ax*0.5);
    var fCosPitch = Math.cos(ax*0.5);
    var fSinYaw = Math.sin(ay*0.5);
    var fCosYaw = Math.cos(ay*0.5);
    var fSinRoll = Math.sin(az*0.5);
    var fCosRoll = Math.cos(az*0.5);
    var fCosPitchCosYaw = fCosPitch*fCosYaw;
    var fSinPitchSinYaw = fSinPitch*fSinYaw;
    this.x = fSinRoll*fCosPitchCosYaw - fCosRoll*fSinPitchSinYaw;
    this.y = fCosRoll*fSinPitch*fCosYaw + fSinRoll*fCosPitch*fSinYaw;
    this.z = fCosRoll*fCosPitch*fSinYaw - fSinRoll*fSinPitch*fCosYaw;
    this.w = fCosRoll*fCosPitchCosYaw + fSinRoll*fSinPitchSinYaw;
  },
  modulo : function() {
    return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z * this.w*this.w);
  },
  conjugate : function(a) {
    return new Quaternion(-a.x, -a.y, -a.z, a.w);
  },
  createFromAxisAngle : function(ax, ay, az, useDegrees) {
    if(useDegrees) {
      ax *= DEGTORAD;
      ay *= DEGTORAD;
      az *= DEGTORAD;
    }
    var fSinPitch = Math.sin(ax*0.5);
    var fCosPitch = Math.cos(ax*0.5);
    var fSinYaw = Math.sin(ay*0.5);
    var fCosYaw = Math.cos(ay*0.5);
    var fSinRoll = Math.sin(az*0.5);
    var fCosRoll = Math.cos(az*0.5);
    var fCosPitchCosYaw = fCosPitch*fCosYaw;
    var fSinPitchSinYaw = fSinPitch*fSinYaw;
    var q = new Quaternion();
    q.x = fSinRoll*fCosPitchCosYaw - fCosRoll*fSinPitchSinYaw;
    q.y = fCosRoll*fSinPitch*fCosYaw + fSinRoll*fCosPitch*fSinYaw;
    q.z = fCosRoll*fCosPitch*fSinYaw - fSinRoll*fSinPitch*fCosYaw;
    q.w = fCosRoll*fCosPitchCosYaw + fSinRoll*fSinPitchSinYaw;
    return q;
  },
  add : function(a, b) {
    return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
  },
  sub : function(a, b) {
    return new Quaternion(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
  },
  dot : function(a, b) {
    return (a.x*b.x) + (a.y*b.y) + (a.z*b.z) + (a.w*b.w);
  },
  multiply : function(a, b) {
    var c = new Quaternion();
    c.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
    c.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
    c.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
    c.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
    return c;
  },
  mult : function(b) {
    var ax = this.x;
    var ay = this.y;
    var az = this.z;
    var aw = this.w;
    this.x = aw*b.x + ax*b.w + ay*b.z - az*b.y;
    this.y = aw*b.y - ax*b.z + ay*b.w + az*b.x;
    this.z = aw*b.z + ax*b.y - ay*b.x + az*b.w;
    this.w = aw*b.w - ax*b.x - ay*b.y - az*b.z;
  },
  normalize : function() {
    var len = this.modulo();
    if(Math.abs(len) < this.EPSILON) {
      this.x = this.y = this.z = 0.0;
      this.w = 1.0;
    }else {
      var m = 1/len;
      this.x *= m;
      this.y *= m;
      this.z *= m;
      this.w *= m;
    }
  },
  slerp : function(qa, qb, alpha) {
    var angle = qa.w*qb.w + qa.x*qb.x + qa.y*qb.y + qa.z*qb.z;
    if(angle < 0.0) {
      qa.x *= -1.0;
      qa.y *= -1.0;
      qa.z *= -1.0;
      qa.w *= -1.0;
      angle *= -1.0;
    }
    var scale;
    var invscale;
    if((angle + 1.0) > this.EPSILON) {
      if((1.0 - angle) >= this.EPSILON) {
        var theta = Math.acos(angle);
        var invsintheta = 1.0/Math.sin(theta);
        scale = Math.sin(theta*(1.0 - alpha))*invsintheta;
        invscale = Math.sin(theta*alpha)*invsintheta;
      }else {
        scale = 1.0 - alpha;
        invscale = alpha;
      }
    }else {
      qb.y = -qa.y;
      qb.x = qa.x;
      qb.w = -qa.w;
      qb.z = qa.z;
      scale = Math.sin(Math.PI*(0.5 - alpha));
      invscale = Math.sin(Math.PI*alpha);
    }
    return new Quaternion(scale*qa.x + invscale*qb.x, 
                          scale*qa.y + invscale*qb.y,
                          scale*qa.z + invscale*qb.z,
                          scale*qa.w + invscale*qb.w );
  },
  toEuler : function() {
    var euler = {x:0, y:0, z:0};
    var q = this;
    var test = q.x*q.y + q.z*q.w;
    if(test > 0.499) {
      euler.x = 2*Math.atan2(q.x, q.w);
      euler.y = Math.PI/2;
      euler.z = 0;
      return euler;
    }
    if(test < -0.499) {
      euler.x = -2*Math.atan2(q.x, q.w);
      euler.y = -Math.PI/2;
      euler.z = 0;
      return euler;
    }
    var sqx = q.x*q.x;
    var sqy = q.y*q*y;
    var sqz = q.z*q.z;
    euler.x = Math.atan2(2*q.y*q.w - 2*q.x*q.z, 1 - 2*sqy - 2*sqz);
    euler.y = Math.asin(2*test);
    euler.z = Math.atan2(2*q.x*q.w - 2*q.y*q.z , 1 - 2*sqx - 2*sqz);
    return euler;
  }
});

var Scene3D = Class.create({
  initialize : function() {
    this.objects = [];
    this.materials = [];
  },
  addObject : function(object) {
    this.objects.push(object);
  },
  removeObject : function(object) {
    for(var i=0; i<this.objects.length; i++) {
      if(this.objects[i] == object) {
        this.objects.splice(i, 1);
      }
    }
  }
});

var WireframeMaterial = Class.create({
  initialize : function(canvas, color, thickness) {
    this.context = canvas.getContext('2d');
    this.context.strokeStyle = color || 'rgba(255, 0, 255, 1)';
    this.context.lineWidth = thickness || 1.0;
  },
  drawTriangle : function(tri, screen) {
    var point = tri.v0.project(screen);
    this.context.beginPath();
    this.context.moveTo(point.x, point.y);
    point = tri.v1.project(screen);
    this.context.lineTo(point.x, point.y);
    point = tri.v2.project(screen);
    this.context.lineTo(point.x, point.y);
    point = tri.v0.project(screen);
    this.context.lineTo(point.x, point.y);
    this.context.closePath();
    this.context.stroke();
  }
});

var Screen = Class.create({
  initialize : function(width, height, fieldOfView) {
    this.width = width;
    this.height = height;
    this.projectionCenter = new Point(width*0.5, height*0.5);
    this.fieldOfView = fieldOfView;
    this.focalLength = width*0.5*(1/Math.tan(fieldOfView*0.5*Math.PI/180));
  }
});

var BasicRenderEngine = Class.create({
  initialize : function(canvas, screen, time) {
    this.width = canvas.width;
    this.height = canvas.height;
    this.context = canvas.getContext('2d');
    this.screen = screen;
    this.time = time || 100;
    this.isPlay = false;
    this.setBackground(this.context.createLinearGradient(0, 0, 0, 300));
  },
  setTime : function(time) {
    this.time = time;
  },
  setBackground : function(grad) {
    grad.addColorStop(0, 'rgb(0, 0, 0)');
    grad.addColorStop(0.7, 'rgb(16, 16, 16)');
    grad.addColorStop(0.8, 'rgb(32, 32, 32)');
    grad.addColorStop(0.9, 'rgb(48, 48, 48)');
    grad.addColorStop(1, 'rgb(64, 64, 64)');
    this.context.fillStyle = grad;
    this.context.fillRect(0, 0, this.width, this.height);
  },
  renderScene : function(scene, angle) {
    var self = this;
    if(!this.isPlay) {
      this.timerID = setInterval(function(){self.render(scene, angle);}, this.time);
      this.isPlay = true;
    }
  },
  stop : function() {
    if(this.isPlay) {
      clearInterval(this.timerID);
      this.isPlay = false;
    }
  },
  render : function(scene, angle) {
    var objects = scene.objects;
    this.context.fillRect(0, 0, this.width, this.height);
    for(var i=0, m_len=objects.length; i<m_len; i++) {
      for(var j=0, len=objects[i].length; j<len; j++) {
        objects[i][j].rotateX(angle);
        objects[i][j].rotateY(angle);
        objects[i][j].rotateZ(angle);
        objects[i][j].draw(this.screen);
      }
    }
  }
});

================================================
FILE: draw/mobius.js
================================================
/**
 * Mobius Strip Maker
 */
var MobiusStrip = (function() {
  var _context = null,
      _width = null,
      _height = null,
      _scale = 60,
      _fov = 250,
      _points = [],
      _numPoints = 0,
      _isPlay = false,
      _timerID = null,
      // public methods
      _init = function(context, n) {
        _context = context;
        _width = context.canvas.width;
        _height = context.canvas.height;
        _points = [];
        _setStyle(context.createLinearGradient(0, 0, 0, 300));
        _setPoints(n);
      },
      _play = function(t, angle) {
        if(!_isPlay) {
          _timerID = setInterval(function() {
            _render(angle)
          }, t);
          _isPlay = true;
        }
      },
      _stop = function() {
        if(_isPlay) {
          clearInterval(_timerID);
          _isPlay = false;
        }
      },
      // private methods
      _setStyle = function(grad) {
        grad.addColorStop(0, 'rgb(0, 0, 0)');
        grad.addColorStop(0.7, 'rgb(16, 16, 16)');
        grad.addColorStop(0.8, 'rgb(32, 32, 32)');
        grad.addColorStop(0.9, 'rgb(48, 48, 48)');
        grad.addColorStop(1, 'rgb(64, 64, 64)');
        _context.fillStyle = grad;
        _context.strokeStyle = 'rgb(0, 255, 160)';
        _context.fillRect(0, 0, _width, _height);
      },
      _setPoints = function(num) {
        var s, t, k, n = 0, point;
        for(var i=0; i<=2*Math.PI*num; i++) {
          for(var j=-num/8; j<=num/8; j++) {
            s = i/num; t = j/10;
            k = 1 + t*Math.cos(s/2);
            point = [_scale*k*Math.cos(s),
                     _scale*k*Math.sin(s),
                     _scale*t*Math.sin(s/2)];
            _points.push(point);
            n++;
          }
        }
        _numPoints = n;
      },
      _render = function(angle) {
        _context.fillRect(0, 0, _width, _height);
        for(var i=0; i<_numPoints; i++)	{
          _rotateX(_points[i], angle);
          _rotateY(_points[i], angle);
          _rotateZ(_points[i], angle);
          _draw(_points[i]);
        }
      },
      _draw = function(point3d) {
        var scale = _fov/(_fov + point3d[2]),
            x = (point3d[0]*scale) + (_width >> 1),
            y = (point3d[1]*scale) + (_height >> 1);
        _context.lineWidth= scale << 1;
        _context.beginPath();
        _context.moveTo(x, y);
        _context.lineTo(x + scale, y);
        _context.stroke();
      },
      _rotateX = function(point3d, angle) {
        var y = point3d[1],
            z = point3d[2],
            c = Math.cos(angle),
            s = Math.sin(angle),
            ty = y,
            tz = z;
        y = ty*c - tz*s;
        z = ty*s + tz*c;
        point3d[1] = y;
        point3d[2] = z;
      },
      _rotateY = function(point3d, angle) {
        var x = point3d[0],
            z = point3d[2],
            c = Math.cos(angle),
            s = Math.sin(angle),
            tz = z,
            tx = x;
        x = tx*c + tz*s;
        z = tz*c - tx*s;
        point3d[0] = x;
        point3d[2] = z;
      },
      _rotateZ = function(point3d, angle) {
        var x = point3d[0],
            y = point3d[1],
            c = Math.cos(angle),
            s = Math.sin(angle),
            tx = x,
            ty = y;
        x = tx*c - ty*s;
        y = tx*s + ty*c;
        point3d[0] = x;
        point3d[1] = y;
      };

  // public APIs
  return {
    init: _init,
    play: _play,
    stop: _stop,
  };
})();

================================================
FILE: draw/webgl/glsample.js
================================================
/**
 * WebGL Tutorial
 * https://developer.mozilla.org/ja/docs/Web/API/WebGL_API
 */

var gl; // WebGL コンテキスト用のグローバル変数

function start() {
  var canvas = document.getElementById("Canvas");

  // GL コンテキストを初期化
  gl = initWebGL(canvas);

  // WebGL を使用できる場合に限り、処理を継続

  if (gl) {
    // クリアカラーを黒色、不透明に設定する
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    // 深度テストを有効化
    gl.enable(gl.DEPTH_TEST);
    // 近くにある物体は、遠くにある物体を覆い隠す
    gl.depthFunc(gl.LEQUAL);
    // カラーバッファや深度バッファをクリアする
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  }
}

function initWebGL(canvas) {
  gl = null;

  try {
    // 標準コンテキストの取得を試みる。失敗した場合は、experimental にフォールバックする。
    gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  } catch(e) {
    console.log(e);
  }

  // GL コンテキストを取得できない場合は終了する
  if (!gl) {
    alert("WebGL を初期化できません。ブラウザはサポートしていないようです。");
    gl = null;
  }

  return gl;
}

================================================
FILE: draw/webgl/webglsample.html
================================================
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="lib/css/style.css">
    <title>WebGL Sample</title>
  </head>
  <body onload="start()">
    <header>
      <h1 class="term">WebGL Sample</h1>
    </header>
    <div class="wrap"><img src="images/lena.jpg" width="256" height="256">
      <canvas id="Canvas" width="256" height="256"></canvas>
    </div>
    <footer> 
      <a href="./index.html" title="index">index</a>
    </footer>
    <script src="lib/js/glsample.js"></script>
  </body>
</html>


================================================
FILE: ml/README.md
================================================
# Machine Learning Module

## description

Machine Learning in JavaScript / TypeScript (+ AngularJS)

### list
- [AROW](https://github.com/wellflat/imageprocessing-labs/tree/master/ml/arow)
- [Decision Tree](https://github.com/wellflat/imageprocessing-labs/blob/master/ml/decisiontree/decisiontree.js)
- [Denoising Autoencoders](https://github.com/wellflat/imageprocessing-labs/tree/master/ml/autoencoder)
- [K-Means++](https://github.com/wellflat/imageprocessing-labs/blob/master/ml/kmeans/kmeans.js)
- [Logistic Regression](https://github.com/wellflat/imageprocessing-labs/blob/master/ml/logistic_regression/logistic_regression.ts)
- [SCW](https://github.com/wellflat/imageprocessing-labs/tree/master/ml/scw)
- [Gradient Boosting(GBDT)](https://github.com/wellflat/imageprocessing-labs/tree/master/ml/gbdt)
- [t-Distributed Stochastic Neighbor Embedding(t-SNE)](https://github.com/wellflat/imageprocessing-labs/tree/master/ml/t-sne)

### sample
[![da](https://github.com/wellflat/imageprocessing-labs/blob/master/images/da_demo.png)](https://rest-term.com/labs/html5/da/)

[![pixel_clustering](https://github.com/wellflat/imageprocessing-labs/blob/master/images/pixel_clustering.jpg)](https://rest-term.com/labs/html5/pixelclustering.html)

[![decision_tree](https://github.com/wellflat/imageprocessing-labs/blob/master/images/decision_tree.png)](https://rest-term.com/labs/html5/dtree.html)

[![t-sne](https://github.com/wellflat/imageprocessing-labs/blob/master/images/tsne.png)](https://rest-term.com/labs/html5/tsne/)

(Tests: Firefox75.0+, Chrome81.0+)

### web sample
[Denoising Autoencoders][DenoisingAutoencoders]

[Pixel Clustering using K-Means++][PixelClustering]

[Decision Tree Learning][DecisionTree]

[t-Distributed Stochastic Neighbor Embedding(t-SNE)][tSNE]

license
----------
Copyright &copy; 2014 wellflat Licensed under the [MIT License][MIT]

[DenoisingAutoencoders]: http://rest-term.com/labs/html5/da/
[PixelClustering]: http://rest-term.com/labs/html5/pixelclustering.html
[DecisionTree]: http://rest-term.com/labs/html5/dtree.html
[tSNE]: https://rest-term.com/labs/html5/tsne/
[MIT]: http://www.opensource.org/licenses/mit-license.php


================================================
FILE: ml/arow/README.md
================================================
# Adaptive Regularization of Weight Vectors (AROW)

* AROW algorithm and LIBSVM format data loader modules  
(JavaScript codes in 'out' directory)
* LIBSVM Data: Classification (Binary Class) [news20.binary](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html#news20.binary)

## usage in TypeScript

```typescript
import {Feature, DataSet} from './types';
import {AROW} from './arow';
import {DataLoader} from './data_loader';

const featureSize: number =
Download .txt
gitextract_72c15x7w/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── cv/
│   ├── corner_detection/
│   │   ├── README.md
│   │   └── cornerdetect.js
│   ├── fft/
│   │   ├── README.md
│   │   ├── fft.js
│   │   ├── filter.js
│   │   ├── qunit-fft-test.js
│   │   └── spectrum.js
│   ├── fisheye_transform/
│   │   ├── README.md
│   │   └── fisheye.js
│   ├── image_filter/
│   │   ├── README.md
│   │   ├── cavin.js
│   │   └── cvsandbox.js
│   ├── lsd/
│   │   ├── .babelrc
│   │   ├── .eslintignore
│   │   ├── .eslintrc.json
│   │   ├── README.md
│   │   ├── jsconfig.json
│   │   ├── line-segment-detector/
│   │   │   ├── .gitignore
│   │   │   ├── README.md
│   │   │   ├── jsconfig.json
│   │   │   ├── package.json
│   │   │   ├── src/
│   │   │   │   ├── funcs.ts
│   │   │   │   ├── lsd.ts
│   │   │   │   └── types.ts
│   │   │   ├── tsconfig.json
│   │   │   └── webpack.config.js
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app.js
│   │   │   ├── funcs.js
│   │   │   ├── index.html
│   │   │   ├── lsd.js
│   │   │   ├── lsd_component.js
│   │   │   └── types.js
│   │   └── webpack.config.js
│   ├── ort_web/
│   │   ├── HelloONNX.vue
│   │   └── README.md
│   ├── pixel_clustering/
│   │   ├── README.md
│   │   ├── kmeans.js
│   │   └── pixelcluster.js
│   ├── poisson_blending/
│   │   ├── README.md
│   │   └── poisson.js
│   ├── stereo_matching/
│   │   ├── README.md
│   │   ├── stereo-core.js
│   │   └── stereo.js
│   └── utils/
│       └── histogram.js
├── draw/
│   ├── README.md
│   ├── heart.js
│   ├── klein.js
│   ├── lib3d.js
│   ├── mobius.js
│   └── webgl/
│       ├── glsample.js
│       └── webglsample.html
└── ml/
    ├── README.md
    ├── arow/
    │   ├── README.md
    │   ├── app.ts
    │   ├── arow.ts
    │   ├── data_loader.ts
    │   ├── out/
    │   │   ├── app.js
    │   │   ├── arow.js
    │   │   ├── data_loader.js
    │   │   └── types.js
    │   └── types.ts
    ├── autoencoder/
    │   ├── css/
    │   │   └── app.css
    │   ├── index.html
    │   ├── out/
    │   │   ├── da.js
    │   │   ├── matrix.js
    │   │   └── vector.js
    │   ├── packages.config
    │   ├── spec/
    │   │   ├── Chutzpah.json
    │   │   ├── Tests/
    │   │   │   ├── da_test.ts
    │   │   │   ├── matrix_t_test.ts
    │   │   │   ├── matrix_test.ts
    │   │   │   ├── vector_t_test.ts
    │   │   │   └── vector_test.ts
    │   │   └── packages.config
    │   └── src/
    │       ├── app.ts
    │       ├── controller.ts
    │       ├── da.ts
    │       ├── matrix.ts
    │       ├── matrix_t.ts
    │       ├── storage.ts
    │       ├── vector.ts
    │       └── vector_t.ts
    ├── datasets/
    │   ├── README.md
    │   ├── boston_data.js
    │   ├── digits_data.ts
    │   ├── iris_data.ts
    │   └── out/
    │       ├── digits_data.js
    │       └── iris_data.js
    ├── decisiontree/
    │   └── decisiontree.js
    ├── gbdt/
    │   ├── README.md
    │   ├── package.json
    │   └── src/
    │       ├── boston_data.js
    │       ├── gradient_boosting.js
    │       ├── index.js
    │       ├── metrics.js
    │       └── regression_tree.js
    ├── kmeans/
    │   └── kmeans.js
    ├── logistic_regression/
    │   ├── logistic_regression.ts
    │   ├── matrix.ts
    │   └── vector.ts
    ├── scw/
    │   ├── README.md
    │   ├── data_loader.ts
    │   ├── out/
    │   │   ├── app.js
    │   │   ├── data_loader.js
    │   │   ├── scw.js
    │   │   └── types.js
    │   ├── scw.ts
    │   └── types.ts
    ├── t-sne/
    │   ├── .babelrc
    │   ├── .eslintrc.json
    │   ├── .gitignore
    │   ├── README.md
    │   ├── package.json
    │   └── src/
    │       ├── digits_data.js
    │       ├── index.js
    │       ├── tsne.js
    │       └── utils.js
    └── utils/
        ├── data_utils.ts
        ├── metrics.ts
        └── preprocessing.ts
Download .txt
SYMBOL INDEX (394 symbols across 46 files)

FILE: cv/image_filter/cavin.js
  function Features2D (line 289) | function Features2D() {}
  function Util (line 308) | function Util() {}

FILE: cv/image_filter/cvsandbox.js
  function CV (line 6) | function CV() {

FILE: cv/lsd/line-segment-detector/src/funcs.ts
  constant M_3_2_PI (line 7) | const M_3_2_PI = (3 * Math.PI) / 2;
  constant M_2__PI (line 8) | const M_2__PI = (2 * Math.PI);
  constant M_LN10 (line 9) | const M_LN10 = 2.30258509299404568402;
  constant NOT_DEF (line 10) | const NOT_DEF = -1024.0;
  constant USED (line 11) | const USED = 1;
  constant NOT_USED (line 12) | const NOT_USED = 0;
  constant RELATIVE_ERROR_FACTOR (line 13) | const RELATIVE_ERROR_FACTOR = 100.0;
  constant DEG_TO_RADS (line 14) | const DEG_TO_RADS = Math.PI / 180;
  constant REFINE_NONE (line 15) | const REFINE_NONE = 0;
  constant REFINE_STD (line 16) | const REFINE_STD = 1;
  constant REFINE_ADV (line 17) | const REFINE_ADV = 2;
  function logGammaLanczos (line 26) | function logGammaLanczos(x: number) {
  function angleDiffSigned (line 46) | function angleDiffSigned(a: number, b: number) {
  function angleDiff (line 58) | function angleDiff(a: number, b: number) {
  function doubleEqual (line 63) | function doubleEqual(a: number, b: number) {
  function AsmallerB_XoverY (line 79) | function AsmallerB_XoverY(a: Edge, b: Edge) {

FILE: cv/lsd/line-segment-detector/src/lsd.ts
  class LSD (line 27) | class LSD {
    method constructor (line 37) | constructor(
    method detect (line 46) | detect(image: ImageData) {
    method drawSegments (line 59) | drawSegments(context: CanvasRenderingContext2D, lines: Vec4[], color =...
    method putImageData (line 75) | putImageData(context: CanvasRenderingContext2D) {
    method lsd (line 92) | lsd() {
    method computeLevelLineAngles (line 162) | computeLevelLineAngles(threshold: number, nBins: number) {
    method regionGrow (line 236) | regionGrow(s: Point, reg: RegionPoint[], regAngle: number, prec: numbe...
    method isAligned (line 278) | isAligned(x: number, y: number, theta: number, prec: number) {
    method region2Rect (line 299) | region2Rect(reg: RegionPoint[], regAngle: number, prec: number, p: num...
    method getTheta (line 350) | getTheta(reg: RegionPoint[], x: number, y: number, regAngle: number, p...
    method refine (line 377) | refine(reg: RegionPoint[], regAngle: number, prec: number, p: number, ...
    method reduceRegionRadius (line 412) | reduceRegionRadius(reg: RegionPoint[], regAngle: number, prec: number,...
    method improveRect (line 440) | improveRect(rect: Rect) {
    method rectNfa (line 508) | rectNfa(rect: Rect) {
    method nfa (line 615) | nfa(n: number, k: number, p: number) {
    method gaussianBlur (line 652) | gaussianBlur(imageData: Uint8ClampedArray, kSize: number, sigma: numbe...
    method getGaussianKernel (line 706) | getGaussianKernel(kSize: number, sigma: number) {
    method reshape (line 724) | reshape(image: ImageData) {
    method at (line 734) | at(data: Uint8Array|Float64Array, p: Point) {
    method row (line 738) | row(data: Float64Array, rowIndex: number) {
    method setRow (line 743) | setRow(data: Float64Array, index: number, value: number) {
    method setCol (line 752) | setCol(data: Float64Array, index: number, value: number) {

FILE: cv/lsd/line-segment-detector/src/types.ts
  class Vec4 (line 1) | class Vec4 {
    method constructor (line 2) | constructor(public x1 = 0, public y1 = 0, public x2 = 0, public y2 = 0...
  class Point (line 5) | class Point {
    method constructor (line 6) | constructor(public x = 0.0, public y = 0.0) { }
  class CoorList (line 9) | class CoorList {
    method constructor (line 13) | constructor() {
  class RegionPoint (line 18) | class RegionPoint {
    method constructor (line 19) | constructor(public x = 0, public y = 0, public angle = 0.0, public mod...
  class Rect (line 22) | class Rect {
    method constructor (line 23) | constructor(
    method copy (line 29) | copy(rect: Rect) {
  class Edge (line 46) | class Edge {
    method constructor (line 50) | constructor() {

FILE: cv/lsd/src/funcs.js
  constant M_3_2_PI (line 5) | const M_3_2_PI = (3 * Math.PI) / 2;
  constant M_2__PI (line 6) | const M_2__PI = (2 * Math.PI);
  constant M_LN10 (line 7) | const M_LN10 = 2.30258509299404568402;
  constant NOT_DEF (line 8) | const NOT_DEF = -1024.0;
  constant USED (line 9) | const USED = 1;
  constant NOT_USED (line 10) | const NOT_USED = 0;
  constant RELATIVE_ERROR_FACTOR (line 11) | const RELATIVE_ERROR_FACTOR = 100.0;
  constant DEG_TO_RADS (line 12) | const DEG_TO_RADS = Math.PI / 180;
  constant REFINE_NONE (line 13) | const REFINE_NONE = 0;
  constant REFINE_STD (line 14) | const REFINE_STD = 1;
  constant REFINE_ADV (line 15) | const REFINE_ADV = 2;
  function logGammaLanczos (line 24) | function logGammaLanczos(x) {
  function angleDiffSigned (line 50) | function angleDiffSigned(a, b) {
  function angleDiff (line 67) | function angleDiff(a, b) {
  function doubleEqual (line 77) | function doubleEqual(a, b) {
  function AsmallerB_XoverY (line 98) | function AsmallerB_XoverY(a, b) {

FILE: cv/lsd/src/lsd.js
  class LSD (line 27) | class LSD {
    method constructor (line 28) | constructor(
    method detect (line 62) | detect(image) {
    method drawSegments (line 75) | drawSegments(context, lines, color = '#ff0000') {
    method putImageData (line 91) | putImageData(context) {
    method lsd (line 107) | lsd() {
    method computeLevelLineAngles (line 177) | computeLevelLineAngles(threshold, nBins) {
    method regionGrow (line 256) | regionGrow(s, reg, regAngle, prec) {
    method isAligned (line 304) | isAligned(x, y, theta, prec) {
    method region2Rect (line 332) | region2Rect(reg, regAngle, prec, p, rect) {
    method getTheta (line 391) | getTheta(reg, x, y, regAngle, prec) {
    method refine (line 427) | refine(reg, regAngle, prec, p, rect, densityTh) {
    method reduceRegionRadius (line 471) | reduceRegionRadius(reg, regAngle, prec, p, rect, density, densityTh) {
    method improveRect (line 503) | improveRect(rect) {
    method rectNfa (line 575) | rectNfa(rect) {
    method nfa (line 684) | nfa(n, k, p) {
    method gaussianBlur (line 727) | gaussianBlur(imageData, kSize, sigma) {
    method getGaussianKernel (line 786) | getGaussianKernel(kSize, sigma) {
    method reshape (line 807) | reshape(image) {
    method at (line 821) | at(data, p) {
    method row (line 829) | row(data, rowIndex) {
    method setRow (line 840) | setRow(data, index, value) {
    method setCol (line 855) | setCol(data, index, value) {

FILE: cv/lsd/src/lsd_component.js
  class LSDComponent (line 5) | class LSDComponent extends React.Component {
    method constructor (line 6) | constructor(props) {
    method componentDidMount (line 10) | componentDidMount() {
    method componentDidUpdate (line 18) | componentDidUpdate() {
    method apply (line 21) | apply(e) {
    method reset (line 31) | reset(e) {
    method onLoad (line 36) | onLoad() {
    method render (line 44) | render() {

FILE: cv/lsd/src/types.js
  class Vec4 (line 1) | class Vec4 {
    method constructor (line 2) | constructor(x1 = 0, y1 = 0, x2 = 0, y2 = 0) {
  class Point (line 10) | class Point {
    method constructor (line 11) | constructor(x = 0.0, y = 0.0) {
  class CoorList (line 17) | class CoorList {
    method constructor (line 18) | constructor() {
  class RegionPoint (line 25) | class RegionPoint {
    method constructor (line 26) | constructor(x = 0, y = 0, angle = 0.0, modgrad = 0.0, used = null) {
  class Rect (line 36) | class Rect {
    method constructor (line 37) | constructor(
    method copy (line 59) | copy(rect) {
  class Edge (line 76) | class Edge {
    method constructor (line 77) | constructor() {

FILE: cv/pixel_clustering/kmeans.js
  function kmeans (line 8) | function kmeans(samples, ncluster, method) {
  function vq (line 135) | function vq(samples, centroids, code) {

FILE: cv/stereo_matching/stereo-core.js
  function findStereoCorrespondence (line 5) | function findStereoCorrespondence(pair, state) {

FILE: cv/utils/histogram.js
  function self (line 7) | function self() {

FILE: draw/lib3d.js
  function self (line 8) | function self() {

FILE: draw/webgl/glsample.js
  function start (line 8) | function start() {
  function initWebGL (line 28) | function initWebGL(canvas) {

FILE: ml/arow/arow.ts
  class AROW (line 7) | class AROW {
    method constructor (line 13) | constructor(featureSize: number, r: number = 0.1) {
    method predict (line 21) | public predict(x: Feature): number {
    method clear (line 25) | public clear(): void {
    method update (line 31) | public update(x: Feature, label: number): number {
    method computeMargin (line 49) | private computeMargin(x: Feature): number {
    method computeConfidence (line 55) | private computeConfidence(x: Feature): number {

FILE: ml/arow/data_loader.ts
  class DataLoader (line 10) | class DataLoader {
    method data (line 16) | get data(): DataSet {
    method size (line 19) | get size(): number {
    method constructor (line 23) | constructor(filePath: string) {
    method parse (line 30) | private parse(): void {
    method read (line 48) | public static read(filePath: string, callback: Function, complete: Fun...

FILE: ml/arow/out/arow.js
  function AROW (line 3) | function AROW(featureSize, r) {

FILE: ml/arow/out/data_loader.js
  function DataLoader (line 5) | function DataLoader(filePath) {

FILE: ml/arow/types.ts
  type Feature (line 4) | type Feature = { index: number, value: number }[];
  type DataSet (line 5) | type DataSet = { label: number, x: Feature }[];

FILE: ml/autoencoder/out/da.js
  function DenoisingAutoencoders (line 8) | function DenoisingAutoencoders(input, nVisible, nHidden, W, vBias, hBias...

FILE: ml/autoencoder/out/matrix.js
  function Matrix (line 8) | function Matrix(elements) {

FILE: ml/autoencoder/out/vector.js
  function Vector (line 7) | function Vector(elements) {

FILE: ml/autoencoder/src/controller.ts
  type dA (line 4) | type dA = ml.DenoisingAutoencoders;
  type Scope (line 6) | interface Scope extends ng.IScope {
  class Controller (line 26) | class Controller {
    method constructor (line 38) | constructor(private $scope: Scope,
    method train (line 72) | public train(): void {
    method loadModel (line 112) | public loadModel(): void {
    method saveModel (line 125) | public saveModel(): void {
    method deleteModel (line 132) | public deleteModel(): void {
    method createContext (line 139) | private createContext(): CanvasRenderingContext2D {
    method drawGraph (line 151) | private drawGraph(): void {

FILE: ml/autoencoder/src/da.ts
  type dA (line 6) | type dA = ml.DenoisingAutoencoders;
  type f (line 7) | type f = (x: number) => number;
  type Model (line 9) | interface Model {
  class DenoisingAutoencoders (line 13) | class DenoisingAutoencoders implements Model {
    method constructor (line 14) | constructor(private input: Matrix, private nVisible: number, private n...
    method weights (line 22) | get weights(): Matrix { return this.W; }
    method weights (line 23) | set weights(w: Matrix) { this.W = w; }
    method vbias (line 24) | get vbias(): Vector { return this.vBias; }
    method vbias (line 25) | set vbias(b: Vector) { this.vBias = b; }
    method hbias (line 26) | get hbias(): Vector { return this.hBias; }
    method hbias (line 27) | set hbias(b: Vector) { this.hBias = b; }
    method data (line 28) | get data(): Matrix { return this.input; }
    method data (line 29) | set data(input: Matrix) { this.input = input; }
    method time (line 30) | get time(): number { return this.timestamp; }
    method train (line 35) | public train(learningRate: number, corruptionLevel: number): void {
    method reconstruct (line 61) | public reconstruct(matrix: Matrix): Matrix {
    method getCost (line 69) | public getCost(corruptionLevel: number): number {
    method updateTimestamp (line 84) | public updateTimestamp(): void {
    method convertModel (line 89) | public convertModel(value: any): [dA, Date] {
    method getCorruptedInput (line 100) | private getCorruptedInput(input: Matrix, corruptionLevel: number): Mat...
    method getHiddenValues (line 118) | private getHiddenValues(input: Matrix): Matrix {
    method getReconstructedInput (line 125) | private getReconstructedInput(hidden: Matrix): Matrix {
    method binomial (line 131) | private binomial(n: number, p: number): number {

FILE: ml/autoencoder/src/matrix.ts
  class Matrix (line 5) | class Matrix {
    method constructor (line 8) | constructor(elements: number[][]) {
    method shape (line 12) | get shape(): number[] {
    method rows (line 16) | get rows(): number { return this.elements.length; }
    method cols (line 17) | get cols(): number { return this.elements[0].length; }
    method rand (line 19) | static rand(n: number, m: number, round: boolean = false): Matrix {
    method zeros (line 28) | static zeros(n: number, m: number): Matrix {
    method ones (line 32) | static ones(n: number, m: number): Matrix {
    method fill (line 36) | static fill(n: number, m: number, x: number): Matrix {
    method row (line 48) | public row(i: number): Vector {
    method col (line 55) | public col(j: number): Vector {
    method at (line 68) | public at(i: number, j: number): number {
    method add (line 76) | public add(matrix: Matrix): Matrix {
    method subtract (line 83) | public subtract(matrix: Matrix): Matrix {
    method isSameSizeAs (line 90) | private isSameSizeAs(matrix: Matrix): boolean {
    method multiply (line 95) | public multiply(matrix: number | Matrix): Matrix { // Jasmine not supp...
    method dot (line 116) | public dot(matrix: Matrix): Matrix {
    method transpose (line 144) | public transpose(): Matrix {
    method addBias (line 159) | public addBias(bias: Vector): Matrix {
    method sum (line 175) | public sum(axis: number = 0): Vector {
    method mean (line 202) | public mean(axis: number = 0): Vector {
    method max (line 212) | public max(): number {
    method log (line 227) | public log(): Matrix {
    method map (line 231) | public map(fn: Function): Matrix {
    method toString (line 246) | public toString(round: boolean = false): string {
    method setElements (line 261) | private setElements(elements: number[][]) {

FILE: ml/autoencoder/src/matrix_t.ts
  class MatrixT (line 5) | class MatrixT {
    method constructor (line 11) | constructor(elements: any) {
    method shape (line 20) | get shape(): number[] {
    method rows (line 24) | get rows(): number { return this.elements.length; }
    method cols (line 25) | get cols(): number { return this.elements[0].length; }
    method rand (line 27) | static rand(n: number, m: number): MatrixT {
    method zeros (line 31) | static zeros(n: number, m: number): MatrixT {
    method row (line 43) | public row(i: number): VectorT {
    method col (line 50) | public col(j: number): VectorT {
    method at (line 63) | public at(i: number, j: number): number {
    method add (line 70) | public add(matrix: MatrixT): MatrixT {
    method subtract (line 77) | public subtract(matrix: MatrixT): MatrixT {
    method isSameSizeAs (line 84) | private isSameSizeAs(matrix: MatrixT): boolean {
    method multiply (line 90) | public multiply(matrix): MatrixT {
    method dot (line 110) | public dot(matrix): MatrixT {
    method transpose (line 138) | public transpose(): MatrixT {
    method addBias (line 153) | public addBias(bias: VectorT): MatrixT {
    method sum (line 169) | public sum(axis: number = 0): VectorT {
    method mean (line 196) | public mean(axis: number = 0): VectorT {
    method log (line 223) | public log(): MatrixT {
    method map (line 227) | public map(fn: Function): MatrixT {
    method toString (line 242) | public toString(round: boolean = false): string {
    method setElements (line 257) | private setElements(elements: number[][]) {

FILE: ml/autoencoder/src/storage.ts
  class ModelStorage (line 6) | class ModelStorage {
    method constructor (line 8) | constructor(private name: string, private version: number) {
    method upgrade (line 14) | private upgrade(e: any): void {
    method load (line 20) | public load(callback: (data: Object) => void): void {
    method add (line 40) | public add(model: Model, callback: () => void): void {
    method delete (line 59) | public delete(callback: () => void): void {

FILE: ml/autoencoder/src/vector.ts
  class Vector (line 5) | class Vector {
    method constructor (line 7) | constructor(private elements: number[]) { }
    method size (line 9) | get size(): number { return this.elements.length; }
    method create (line 11) | static create(elements: number[]): Vector {
    method rand (line 15) | static rand(n: number): Vector {
    method zeros (line 21) | static zeros(n: number): Vector {
    method arange (line 27) | static arange(n: number): Vector {
    method clone (line 35) | public clone(): Vector {
    method at (line 39) | public at(i: number): number {
    method add (line 44) | public add(vector: Vector): Vector {
    method subtract (line 50) | public subtract(vector: Vector): Vector {
    method multiply (line 56) | public multiply(k: number): Vector {
    method dot (line 60) | public dot(vector: Vector): number {
    method cross (line 73) | public cross(vector: Vector): Vector {
    method mean (line 86) | public mean(): number {
    method toString (line 95) | public toString(): string {
    method map (line 99) | public map(fn: Function): Vector {
    method forEach (line 105) | private forEach(fn: Function): void {

FILE: ml/autoencoder/src/vector_t.ts
  class VectorT (line 5) | class VectorT {
    method constructor (line 10) | constructor(elements: any) {
    method size (line 19) | get size(): number { return this.elements.length; }
    method create (line 21) | static create(elements: Float32Array): VectorT {
    method rand (line 25) | static rand(n: number): VectorT {
    method zeros (line 33) | static zeros(n: number): VectorT {
    method arange (line 37) | static arange(n: number): VectorT {
    method clone (line 45) | public clone(): VectorT {
    method at (line 49) | public at(i: number): number {
    method add (line 54) | public add(vector: VectorT): VectorT {
    method subtract (line 60) | public subtract(vector: VectorT): VectorT {
    method multiply (line 66) | public multiply(k: number): VectorT {
    method dot (line 70) | public dot(vector: VectorT): number {
    method cross (line 83) | public cross(vector: VectorT): VectorT {
    method mean (line 96) | public mean(): number {
    method toString (line 105) | public toString(): string {
    method map (line 117) | public map(fn: Function, size: number): VectorT {
    method forEach (line 123) | private forEach(fn: Function): void {

FILE: ml/gbdt/src/gradient_boosting.js
  class GradientBoostingRegressor (line 8) | class GradientBoostingRegressor {
    method constructor (line 15) | constructor(nEstimators = 100, learningRate = 0.1, depth = 3, lossFunc...
    method fit (line 35) | fit(x, y) {
    method predict (line 52) | predict(x) {

FILE: ml/gbdt/src/metrics.js
  function mse (line 7) | function mse(test, pred) {
  function rmse (line 22) | function rmse(test, pred) {
  function score (line 32) | function score(test, pred) {
  function residual (line 42) | function residual(test, pred) {
  function variance (line 57) | function variance(data) {

FILE: ml/gbdt/src/regression_tree.js
  class RegressionTree (line 1) | class RegressionTree {
    method constructor (line 5) | constructor(depth) {
    method fit (line 19) | fit(x, y) {
    method predict (line 36) | predict(x) {
    method growTree (line 59) | growTree(id, x, y) {
    method searchBestSplit (line 88) | searchBestSplit(id, x, y) {
    method calculateImpurity (line 117) | calculateImpurity(j, threshold, id, x, y) {
  class Node (line 152) | class Node {
    method constructor (line 153) | constructor() {

FILE: ml/kmeans/kmeans.js
  function kmeans (line 8) | function kmeans(samples, ncluster, method) {
  function vq (line 135) | function vq(samples, centroids, code) {

FILE: ml/logistic_regression/logistic_regression.ts
  class LogisticRegression (line 5) | class LogisticRegression {
    method constructor (line 7) | constructor(private input: Matrix, private label: Matrix,
    method fit (line 13) | public fit(learningRate: number, iter: number, l2Reg: number = 0.00, v...
    method train (line 27) | public train(learningRate: number, l2Reg: number = 0.00): void {
    method predict (line 36) | public predict(x: Matrix): Matrix {
    method getLoss (line 41) | public getLoss(): number {
    method softmax (line 56) | private softmax(x: Matrix): Matrix {
    method softmax2 (line 74) | private softmax2(x: Matrix): Matrix {

FILE: ml/logistic_regression/matrix.ts
  class Matrix (line 5) | class Matrix {
    method constructor (line 8) | constructor(elements: number[][]) {
    method shape (line 12) | get shape(): number[] {
    method rows (line 16) | get rows(): number { return this.elements.length; }
    method cols (line 17) | get cols(): number { return this.elements[0].length; }
    method rand (line 19) | static rand(n: number, m: number, round: boolean = false): Matrix {
    method zeros (line 28) | static zeros(n: number, m: number): Matrix {
    method ones (line 32) | static ones(n: number, m: number): Matrix {
    method fill (line 36) | static fill(n: number, m: number, x: number): Matrix {
    method row (line 48) | public row(i: number): Vector {
    method col (line 55) | public col(j: number): Vector {
    method at (line 68) | public at(i: number, j: number): number {
    method add (line 76) | public add(matrix: Matrix): Matrix {
    method subtract (line 83) | public subtract(matrix: Matrix): Matrix {
    method isSameSizeAs (line 90) | private isSameSizeAs(matrix: Matrix): boolean {
    method multiply (line 95) | public multiply(matrix: number | Matrix): Matrix { // Jasmine not supp...
    method dot (line 116) | public dot(matrix: Matrix): Matrix {
    method transpose (line 144) | public transpose(): Matrix {
    method addBias (line 159) | public addBias(bias: Vector): Matrix {
    method sum (line 175) | public sum(axis: number = 0): Vector {
    method mean (line 202) | public mean(axis: number = 0): Vector {
    method max (line 212) | public max(): number {
    method log (line 227) | public log(): Matrix {
    method map (line 231) | public map(fn: Function): Matrix {
    method toString (line 246) | public toString(round: boolean = false): string {
    method setElements (line 261) | private setElements(elements: number[][]) {

FILE: ml/logistic_regression/vector.ts
  class Vector (line 5) | class Vector {
    method constructor (line 7) | constructor(public elements: number[]) { }
    method size (line 9) | get size(): number { return this.elements.length; }
    method create (line 11) | static create(elements: number[]): Vector {
    method rand (line 15) | static rand(n: number): Vector {
    method zeros (line 21) | static zeros(n: number): Vector {
    method arange (line 27) | static arange(n: number): Vector {
    method clone (line 35) | public clone(): Vector {
    method at (line 39) | public at(i: number): number {
    method add (line 44) | public add(vector: Vector): Vector {
    method subtract (line 50) | public subtract(vector: Vector): Vector {
    method multiply (line 56) | public multiply(k: number): Vector {
    method dot (line 60) | public dot(vector: Vector): number {
    method cross (line 73) | public cross(vector: Vector): Vector {
    method mean (line 86) | public mean(): number {
    method toString (line 95) | public toString(): string {
    method map (line 99) | public map(fn: Function): Vector {
    method forEach (line 105) | private forEach(fn: Function): void {

FILE: ml/scw/data_loader.ts
  class DataLoader (line 10) | class DataLoader {
    method data (line 16) | get data(): DataSet {
    method size (line 19) | get size(): number {
    method constructor (line 23) | constructor(filePath: string, featureSize: number = 0) {
    method parse (line 34) | private parse(): void {
    method parsePaddingZero (line 52) | private parsePaddingZero(featureSize: number): void {
    method read (line 68) | public static read(filePath: string, featureSize:number, callback: Fun...

FILE: ml/scw/out/data_loader.js
  function DataLoader (line 5) | function DataLoader(filePath, featureSize) {

FILE: ml/scw/out/scw.js
  function SCW (line 3) | function SCW(n, eta, C, type) {

FILE: ml/scw/scw.ts
  class SCW (line 4) | class SCW {
    method constructor (line 15) | constructor(n: number, eta:number, C:number, type: string = SCW.SCW_I) {
    method predict (line 31) | public predict(x: Float32Array): number {
    method update (line 35) | public update(x: Float32Array, y: number, verbose: boolean = false) {
    method loss (line 50) | public loss(x: Float32Array, y: number): number {
    method calculateAlpha (line 54) | private calculateAlpha(x: Float32Array, y: number, vt: number): number {
    method calculateBeta (line 78) | private calculateBeta(alpha: number, vt: number): number {
    method updateConfidence (line 87) | private updateConfidence(x: Float32Array): number { // vt
    method updateWeights (line 99) | private updateWeights(alpha: number, x: Float32Array, y: number): void {
    method updateCovariance (line 113) | private updateCovariance(beta: number, x: Float32Array): void {
    method normcdf (line 132) | private normcdf(x: number): number {
    method dot (line 147) | private dot(x: Float32Array, y: Float32Array): number {
    method prod (line 156) | private prod(m1: Float32Array[], m2: Float32Array[]): Float32Array[] {

FILE: ml/scw/types.ts
  type Feature (line 4) | type Feature = { index: number, value: number }[];
  type DataSet (line 5) | type DataSet = { label: number, x: Feature | Float32Array }[];

FILE: ml/t-sne/src/tsne.js
  class tSNE (line 8) | class tSNE {
    method constructor (line 14) | constructor(data, params) {
    method init (line 28) | init() {
    method compute (line 47) | async compute(iter) {
    method iterator (line 64) | *iterator(iter) {
    method stepGradient (line 83) | stepGradient(P, step, t) {
    method calculateCostGrad (line 120) | calculateCostGrad(Y, P, iter) {
    method computeP (line 153) | computeP() {
    method calculateEntropy (line 206) | calculateEntropy(probs, i) {
    method calculateProbs (line 225) | calculateProbs(D, sigma, i, P) {
    method computeQ (line 247) | computeQ(Y) {
    method sampleInitialSolution (line 275) | sampleInitialSolution() {
    method generateRandom (line 297) | generateRandom(n, mu, std) {
    method calculateL2Distance (line 322) | calculateL2Distance(x1, x2) {
    method calculatePairwiseDistance (line 335) | calculatePairwiseDistance(X) {

FILE: ml/t-sne/src/utils.js
  function clone (line 9) | function clone(src) {
  function writeResult (line 26) | async function writeResult(fileName, result) {

FILE: ml/utils/data_utils.ts
  function splitData (line 1) | function splitData(data: [number[][], number[]], testSize: number = 0.2)...
  function createSample (line 13) | function createSample(d: number, n: number): number[][] {
  function createLabel (line 24) | function createLabel(d: number, c: number, n: number): number[][] {
  function randn (line 39) | function randn(m = 0.0, v = 1.0): number {

FILE: ml/utils/metrics.ts
  class Metrics (line 5) | class Metrics {
    method accuracy (line 6) | static accuracy(label: Matrix, pred: Matrix): number {
    method precision (line 21) | static precision(label: Matrix, pred: Matrix): number {
    method recall (line 43) | static recall(label: Matrix, pred: Matrix): number {
    method f1score (line 66) | static f1score(label: Matrix, pred: Matrix): number {
    method confusionmatrix (line 72) | static confusionmatrix(label: Matrix, pred: Matrix): number[][] {
    method argmax (line 78) | static argmax(arr: number[]): number {

FILE: ml/utils/preprocessing.ts
  class Preprocessing (line 5) | class Preprocessing {
    method scale (line 8) | static scale(data: number[][]): Matrix {
    method binalizeLabel (line 22) | static binalizeLabel(labels: number[]): number[][] {
    method splitData (line 37) | static splitData(data: [number[][], number[]],
Condensed preview — 125 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,330K chars).
[
  {
    "path": ".gitattributes",
    "chars": 34,
    "preview": "*.ts linguist-language=JavaScript\n"
  },
  {
    "path": ".gitignore",
    "chars": 381,
    "preview": "## macOS\n.DS_Store\n\n## emacs\n*~\n\\#*\n.\\#*\n\n## vim\n*.swp\n*.swo\n\n## VSCode\n.vscode/\n\n## PROJECT::GENERAL\nlogs/\n*.log\nnpm-de"
  },
  {
    "path": "LICENSE",
    "chars": 1075,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 wellflat\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "README.md",
    "chars": 1132,
    "preview": "## Image processing and Machine learning labs &ensp; [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?"
  },
  {
    "path": "cv/corner_detection/README.md",
    "chars": 982,
    "preview": "# Corner Detection Module\n\n## description\n\nCorner detection using Harris operator\n\nsee also [blog entry][entry]\n\n### sam"
  },
  {
    "path": "cv/corner_detection/cornerdetect.js",
    "chars": 7095,
    "preview": "/**\n * Corner Detector module\n */\n(function() {\n  var CornerDetector;  // top-level namespace\n  var _root = this;    // "
  },
  {
    "path": "cv/fft/README.md",
    "chars": 2619,
    "preview": "# Fast Fourier Transform (FFT) Module\n\n## description\n\n1D-FFT/IFFT, 2D-FFT/IFFT, Frequency Filtering\n\nsee also [blog ent"
  },
  {
    "path": "cv/fft/fft.js",
    "chars": 10230,
    "preview": "/**\n * Fast Fourier Transform module\n * 1D-FFT/IFFT, 2D-FFT/IFFT (radix-2)\n */\n(function() {\n  var FFT;           // top"
  },
  {
    "path": "cv/fft/filter.js",
    "chars": 3012,
    "preview": "/**\n * Spatial Frequency Filtering\n * High-pass/Low-pass/Band-pass Filter\n * Windowing using hamming window\n */\n(functio"
  },
  {
    "path": "cv/fft/qunit-fft-test.js",
    "chars": 1831,
    "preview": "module(\"1D/2D-FFT/IFFT\");\nasyncTest(\"FFT module tests\", function() {\n  try {\n    var image = new Image(),\n        canvas"
  },
  {
    "path": "cv/fft/spectrum.js",
    "chars": 1643,
    "preview": "/**\n * FFT Power Spectrum Viewer\n */\n(function() {\n  var SpectrumViewer;  // top-level namespace\n  var _root = this;    "
  },
  {
    "path": "cv/fisheye_transform/README.md",
    "chars": 838,
    "preview": "# Fish-Eye Transform Module\n\n## description\n\nCircular Fish-Eye transform\n\nsee also [blog entry][entry]\n\n### sample\n[![fi"
  },
  {
    "path": "cv/fisheye_transform/fisheye.js",
    "chars": 3358,
    "preview": "/**\n * Fish-Eye Transform module\n */\n(function() {\n  var Fisheye;        // top-level namespace\n  var _root = this;   //"
  },
  {
    "path": "cv/image_filter/README.md",
    "chars": 1077,
    "preview": "# Image Processing Filters\n\n## description\n\nImage processing filters\n\n* Convolution Filter\n\n[![image_filter](https://raw"
  },
  {
    "path": "cv/image_filter/cavin.js",
    "chars": 9531,
    "preview": "/**\n * Cavin.js\n * Computer Vision and Image Processing Library for HTML5 Canvas\n */\n(function() {\n  /**\n   * intialize\n"
  },
  {
    "path": "cv/image_filter/cvsandbox.js",
    "chars": 6928,
    "preview": "/**\n * Computer Vision Modules using Sandbox Pattern\n */\n\n/* CV: Sandbox constructor */\nfunction CV() {\n  var args = Arr"
  },
  {
    "path": "cv/lsd/.babelrc",
    "chars": 487,
    "preview": "{\r\n    \"presets\": [\"react\", \"es2015\", \"stage-0\"],\r\n    \"plugins\": [\r\n    ],\r\n    \"env\": {\r\n        \"development\": {\r\n   "
  },
  {
    "path": "cv/lsd/.eslintignore",
    "chars": 25,
    "preview": "webpack.config.js\r\ndst/\r\n"
  },
  {
    "path": "cv/lsd/.eslintrc.json",
    "chars": 723,
    "preview": "{\n    \"env\": {\n        \"browser\": true,\n        \"node\": true,\n        \"commonjs\": true,\n        \"es6\": true\n    },\n    \""
  },
  {
    "path": "cv/lsd/README.md",
    "chars": 1944,
    "preview": "# Line Segment Detector Module\n\n## description\n\nLine detection using Line Segment Detector ([LSD][IPOL]) algorithm\n\n![ls"
  },
  {
    "path": "cv/lsd/jsconfig.json",
    "chars": 88,
    "preview": "{\n    \"compilerOptions\": {\n        \"target\": \"es6\",\n        \"module\": \"commonjs\"\n    }\n}"
  },
  {
    "path": "cv/lsd/line-segment-detector/.gitignore",
    "chars": 19,
    "preview": "node_modules\r\ndst\r\n"
  },
  {
    "path": "cv/lsd/line-segment-detector/README.md",
    "chars": 2059,
    "preview": "# Line Segment Detector Module\n\n## description\n\nLine detection using Line Segment Detector ([LSD][IPOL]) algorithm\n\n![ls"
  },
  {
    "path": "cv/lsd/line-segment-detector/jsconfig.json",
    "chars": 88,
    "preview": "{\n    \"compilerOptions\": {\n        \"target\": \"es6\",\n        \"module\": \"commonjs\"\n    }\n}"
  },
  {
    "path": "cv/lsd/line-segment-detector/package.json",
    "chars": 618,
    "preview": "{\n  \"name\": \"line-segment-detector.js\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Line Segment Detector\",\n  \"main\": \"./dst"
  },
  {
    "path": "cv/lsd/line-segment-detector/src/funcs.ts",
    "chars": 2458,
    "preview": "import { Edge } from './types';\n\n/**\n * constants and utility math functions\n */\n\nconst M_3_2_PI = (3 * Math.PI) / 2;\nco"
  },
  {
    "path": "cv/lsd/line-segment-detector/src/lsd.ts",
    "chars": 27653,
    "preview": "/**\n * Line Segment Detector (LSD) module\n * @author https://github.com/wellflat\n */\n\nimport * as funcs from './funcs';\n"
  },
  {
    "path": "cv/lsd/line-segment-detector/src/types.ts",
    "chars": 1258,
    "preview": "class Vec4 {\n    constructor(public x1 = 0, public y1 = 0, public x2 = 0, public y2 = 0) { }\n}\n\nclass Point {\n    constr"
  },
  {
    "path": "cv/lsd/line-segment-detector/tsconfig.json",
    "chars": 623,
    "preview": "{\r\n    \"compileOnSave\": true,\r\n    \"compilerOptions\": {\r\n        \"module\": \"commonjs\",\r\n        \"target\": \"es5\",\r\n      "
  },
  {
    "path": "cv/lsd/line-segment-detector/webpack.config.js",
    "chars": 587,
    "preview": "const webpack = require('webpack');\nconst path = require('path');\n\nmodule.exports = {\n    entry: path.join(__dirname, '."
  },
  {
    "path": "cv/lsd/package.json",
    "chars": 1173,
    "preview": "{\n  \"name\": \"lsd\",\n  \"version\": \"1.0.0\",\n  \"description\": \"LSD: Line Segment Detector\",\n  \"main\": \"src/app.js\",\n  \"scrip"
  },
  {
    "path": "cv/lsd/src/app.js",
    "chars": 2905,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport injectTapEventPlugin from 'react-tap-event-plugin';"
  },
  {
    "path": "cv/lsd/src/funcs.js",
    "chars": 2517,
    "preview": "/**\n * constants and utility math functions\n */\n\nconst M_3_2_PI = (3 * Math.PI) / 2;\nconst M_2__PI = (2 * Math.PI);\ncons"
  },
  {
    "path": "cv/lsd/src/index.html",
    "chars": 237,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\"/>\n    <title>Line"
  },
  {
    "path": "cv/lsd/src/lsd.js",
    "chars": 29083,
    "preview": "/**\n * Line Segment Detector (LSD) module\n * @author https://github.com/wellflat\n */\n\nimport * as funcs from './funcs';\n"
  },
  {
    "path": "cv/lsd/src/lsd_component.js",
    "chars": 1948,
    "preview": "import React from 'react';\nimport RaisedButton from 'material-ui/RaisedButton';\nimport LSD from './lsd';\n\nexport default"
  },
  {
    "path": "cv/lsd/src/types.js",
    "chars": 1733,
    "preview": "class Vec4 {\n    constructor(x1 = 0, y1 = 0, x2 = 0, y2 = 0) {\n        this.x1 = x1;\n        this.y1 = y1;\n        this."
  },
  {
    "path": "cv/lsd/webpack.config.js",
    "chars": 1115,
    "preview": "const HtmlWebpackPlugin = require('html-webpack-plugin');\nconst webpack = require('webpack');\n\nmodule.exports = {\n    en"
  },
  {
    "path": "cv/ort_web/HelloONNX.vue",
    "chars": 3616,
    "preview": "<template>\n  <div class=\"hello\">\n    <h1>{{ msg }}</h1>\n    <canvas width=\"32\" height=\"32\" ref=\"canvas\"></canvas>\n    <b"
  },
  {
    "path": "cv/ort_web/README.md",
    "chars": 309,
    "preview": "## Image Classification using ONNX Runtime for Web (ORT Web) \n\nthis example is the [CIFAR-10](https://www.cs.toronto.edu"
  },
  {
    "path": "cv/pixel_clustering/README.md",
    "chars": 1038,
    "preview": "# Pixel Clustering Module\n\n## description\n\nPixel clustering using k-means++ algorithm\n\nsee also [blog entry][entry]\n\n###"
  },
  {
    "path": "cv/pixel_clustering/kmeans.js",
    "chars": 4972,
    "preview": "/**\n * provides routines for k-means clustering, generating code books,\n * and quantizing vectors by comparing them with"
  },
  {
    "path": "cv/pixel_clustering/pixelcluster.js",
    "chars": 9853,
    "preview": "/**\n * Pixel Clustering module\n * http://rest-term.com\n */\n(function() {\n  var PixelCluster;  // top-level namaspace\n  v"
  },
  {
    "path": "cv/poisson_blending/README.md",
    "chars": 900,
    "preview": "# Poisson Image Editing Module\n\n## description\n\nImage composition using Poisson Image Editing algorithm\n\nsee also [blog "
  },
  {
    "path": "cv/poisson_blending/poisson.js",
    "chars": 5965,
    "preview": "/**\n * Poisson Image Editing module\n * http://rest-term.com\n */\n(function() {\n  var Poisson;       // top-level namaspac"
  },
  {
    "path": "cv/stereo_matching/README.md",
    "chars": 534,
    "preview": "# Stereo Matching Module\n\n## description\n\ncomputes the disparity map using naive block matching\n\nsee also [blog entry][e"
  },
  {
    "path": "cv/stereo_matching/stereo-core.js",
    "chars": 1744,
    "preview": "/**\n *  computes the disparity for the rectified stereo pair,\n *  naive implementation without using dynamic programming"
  },
  {
    "path": "cv/stereo_matching/stereo.js",
    "chars": 3669,
    "preview": "/**\n * Stereo Matching module using Web Workers\n */\n(function() {\n  var Stereo;        // top-level namespace\n  var _roo"
  },
  {
    "path": "cv/utils/histogram.js",
    "chars": 2196,
    "preview": "/**\n * Image Histogram Caluculator using Web Worker API\n */\nvar Class = {\n  create : function() {\n    var properties = a"
  },
  {
    "path": "draw/README.md",
    "chars": 697,
    "preview": "# 3D Shapes Drawing\n\n## description\n\nDrawing 3D shapes (pseudo 3D)\n\n[![3d_drawing](https://raw.github.com/wiki/wellflat/"
  },
  {
    "path": "draw/heart.js",
    "chars": 2832,
    "preview": "/**\n * Heart Surface Maker\n */\nvar Heart = (function() {\n  var _context = null,\n      _width = null,\n      _height = nul"
  },
  {
    "path": "draw/klein.js",
    "chars": 3723,
    "preview": "/**\n * Klein's Bottle Maker\n */\nvar KleinBottle = (function() {\n  var _context = null,\n      _width = null,\n      _heigh"
  },
  {
    "path": "draw/lib3d.js",
    "chars": 11678,
    "preview": "/**\n * My 3D Library v.0.0.2\n * \n */\nvar Class = {\n  create : function() {\n    var properties = arguments[0];\n    functi"
  },
  {
    "path": "draw/mobius.js",
    "chars": 3464,
    "preview": "/**\n * Mobius Strip Maker\n */\nvar MobiusStrip = (function() {\n  var _context = null,\n      _width = null,\n      _height "
  },
  {
    "path": "draw/webgl/glsample.js",
    "chars": 893,
    "preview": "/**\n * WebGL Tutorial\n * https://developer.mozilla.org/ja/docs/Web/API/WebGL_API\n */\n\nvar gl; // WebGL コンテキスト用のグローバル変数\n\n"
  },
  {
    "path": "draw/webgl/webglsample.html",
    "chars": 567,
    "preview": "<!DOCTYPE html>\n<html lang=\"ja\">\n  <head>\n    <meta charset=\"utf-8\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"li"
  },
  {
    "path": "ml/README.md",
    "chars": 2164,
    "preview": "# Machine Learning Module\n\n## description\n\nMachine Learning in JavaScript / TypeScript (+ AngularJS)\n\n### list\n- [AROW]("
  },
  {
    "path": "ml/arow/README.md",
    "chars": 1861,
    "preview": "# Adaptive Regularization of Weight Vectors (AROW)\n\n* AROW algorithm and LIBSVM format data loader modules  \n(JavaScript"
  },
  {
    "path": "ml/arow/app.ts",
    "chars": 1528,
    "preview": "import {Feature, DataSet} from './types';\nimport {AROW} from './arow';\nimport {DataLoader} from './data_loader';\n\nconst"
  },
  {
    "path": "ml/arow/arow.ts",
    "chars": 1759,
    "preview": "/**\n * AROW (Adaptive Regularization of Weight Vectors) class\n */\n\nimport {Feature, DataSet} from './types';\n\nexport cla"
  },
  {
    "path": "ml/arow/data_loader.ts",
    "chars": 2404,
    "preview": "/**\n * Data loader for LIBSVM data format\n * <label> <index1>:<value1> <index2>:<value2> ... \\n\n */\n\nimport * as fs from"
  },
  {
    "path": "ml/arow/out/app.js",
    "chars": 1475,
    "preview": "\"use strict\";\nvar arow_1 = require('./arow');\nvar data_loader_1 = require('./data_loader');\nvar featureSize = 1355191;\nv"
  },
  {
    "path": "ml/arow/out/arow.js",
    "chars": 1757,
    "preview": "\"use strict\";\nvar AROW = (function () {\n    function AROW(featureSize, r) {\n        if (r === void 0) { r = 0.1; }\n     "
  },
  {
    "path": "ml/arow/out/data_loader.js",
    "chars": 2447,
    "preview": "\"use strict\";\nvar fs = require('fs');\nvar readline = require('readline');\nvar DataLoader = (function () {\n    function D"
  },
  {
    "path": "ml/arow/out/types.js",
    "chars": 47,
    "preview": "\"use strict\";\n//# sourceMappingURL=types.js.map"
  },
  {
    "path": "ml/arow/types.ts",
    "chars": 181,
    "preview": "/**\n * Shared types across multiple machine learning components.\n */\nexport type Feature = { index: number, value: numbe"
  },
  {
    "path": "ml/autoencoder/css/app.css",
    "chars": 406,
    "preview": "body {\n    color: #333;\n    font: 1.0em normal Consolas, sans-serif;\n}\n\nspan {\n    font-style: italic;\n}\n\npre {\r\n    co"
  },
  {
    "path": "ml/autoencoder/index.html",
    "chars": 3313,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"utf-8\" />\r\n    <title>TypeScript Practice: Deep Learning<"
  },
  {
    "path": "ml/autoencoder/out/da.js",
    "chars": 6463,
    "preview": "/**\r\n * Denoising Autoencoders class\r\n * author @wellflat\r\n */\r\nvar ml;\r\n(function (ml) {\r\n    var DenoisingAutoencoders"
  },
  {
    "path": "ml/autoencoder/out/matrix.js",
    "chars": 10870,
    "preview": "var ml;\r\n(function (ml) {\r\n    /**\r\n     * Matrix class\r\n     * author @wellflat\r\n     */\r\n    var Matrix = (function ()"
  },
  {
    "path": "ml/autoencoder/out/vector.js",
    "chars": 3881,
    "preview": "var ml;\r\n(function (ml) {\r\n    /**\r\n     * Vector class\r\n     */\r\n    var Vector = (function () {\r\n        function Vect"
  },
  {
    "path": "ml/autoencoder/packages.config",
    "chars": 255,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"angularjs.TypeScript.DefinitelyTyped\" version=\"4.0.4"
  },
  {
    "path": "ml/autoencoder/spec/Chutzpah.json",
    "chars": 192,
    "preview": "{\r\n    \"Framework\": \"jasmine\",\r\n \r\n    \"TestHarnessLocationMode\": \"TestFileAdjacent\",     \r\n \r\n    \"TypeScriptCodeGenTar"
  },
  {
    "path": "ml/autoencoder/spec/Tests/da_test.ts",
    "chars": 1526,
    "preview": "/// <reference path=\"../scripts/typings/jasmine/jasmine.d.ts\" />\r\n/// <reference path=\"../../deeplearning/scripts/vector"
  },
  {
    "path": "ml/autoencoder/spec/Tests/matrix_t_test.ts",
    "chars": 4886,
    "preview": "/// <reference path=\"../scripts/typings/jasmine/jasmine.d.ts\" />\r\n/// <reference path=\"../../deeplearning/scripts/vecto"
  },
  {
    "path": "ml/autoencoder/spec/Tests/matrix_test.ts",
    "chars": 4969,
    "preview": "/// <reference path=\"../scripts/typings/jasmine/jasmine.d.ts\" />\r\n/// <reference path=\"../../deeplearning/scripts/vecto"
  },
  {
    "path": "ml/autoencoder/spec/Tests/vector_t_test.ts",
    "chars": 2464,
    "preview": "/// <reference path=\"../scripts/typings/jasmine/jasmine.d.ts\" />\r\n/// <reference path=\"../../deeplearning/scripts/vecto"
  },
  {
    "path": "ml/autoencoder/spec/Tests/vector_test.ts",
    "chars": 2543,
    "preview": "/// <reference path=\"../scripts/typings/jasmine/jasmine.d.ts\" />\r\n/// <reference path=\"../../deeplearning/scripts/vecto"
  },
  {
    "path": "ml/autoencoder/spec/packages.config",
    "chars": 263,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"jasmine.TypeScript.DefinitelyTyped\" version=\"1.3.7\" "
  },
  {
    "path": "ml/autoencoder/src/app.ts",
    "chars": 146,
    "preview": "\nvar app: ng.IModule = angular.module('Demo', ['ngMaterial']);\napp.config(($mdThemingProvider) => {\n    $mdThemingProvi"
  },
  {
    "path": "ml/autoencoder/src/controller.ts",
    "chars": 6515,
    "preview": "/// <reference path=\"typings/angularjs/angular.d.ts\" />\r\n\r\nmodule DemoApp {\r\n    type dA = ml.DenoisingAutoencoders;\r\n\r"
  },
  {
    "path": "ml/autoencoder/src/da.ts",
    "chars": 5780,
    "preview": "/**\n * Denoising Autoencoders class\n * author @wellflat\n */\nmodule ml {\n    type dA = ml.DenoisingAutoencoders;\n    typ"
  },
  {
    "path": "ml/autoencoder/src/matrix.ts",
    "chars": 9542,
    "preview": "module ml {\n    /**\n     * Matrix class\n     */\n    export class Matrix {\n        private elements: number[][];\n\n      "
  },
  {
    "path": "ml/autoencoder/src/matrix_t.ts",
    "chars": 9610,
    "preview": "module ml {\n    /**\r\n     * Matrix class using Typed Array (Float32Array)\r\n     */\n    export class MatrixT {\n        p"
  },
  {
    "path": "ml/autoencoder/src/storage.ts",
    "chars": 3102,
    "preview": "module ml {\r\n    /**\r\n     * Model Storage class\r\n     * author @wellflat\r\n     */\r\n    export class ModelStorage {\r\n  "
  },
  {
    "path": "ml/autoencoder/src/vector.ts",
    "chars": 3350,
    "preview": "module ml {\n    /**\n     * Vector class\n     */\n    export class Vector {\n\n        constructor(private elements: number"
  },
  {
    "path": "ml/autoencoder/src/vector_t.ts",
    "chars": 4153,
    "preview": "module ml {\n    /**\n     * Vector class using Typed Array (Float32Array)\n     */\n    export class VectorT {\n        pri"
  },
  {
    "path": "ml/datasets/README.md",
    "chars": 366,
    "preview": "# Dataset loading utilities\n\n## description\n\nthis module embeds some small toy datasets for machine learning\n\n* [Boston "
  },
  {
    "path": "ml/datasets/boston_data.js",
    "chars": 40153,
    "preview": "export default {data: [[0.49298,0.0,9.9,0.0,0.544,6.635,82.5,3.3175,4.0,304.0,18.4,396.9,4.54],[3.56868,0.0,18.1,0.0,0.5"
  },
  {
    "path": "ml/datasets/digits_data.ts",
    "chars": 615431,
    "preview": "/* Digits Data Set\n *   http://scikit-learn.org/stable/auto_examples/datasets/plot_digits_last_image.html\n *   classes: "
  },
  {
    "path": "ml/datasets/iris_data.ts",
    "chars": 4161,
    "preview": "/* Iris Data Set\n *   archive.ics.uci.edu/ml/datasets/iris\n *   classes: 3\n *   samples per class: 50\n *   dimensionalit"
  },
  {
    "path": "ml/datasets/out/digits_data.js",
    "chars": 615201,
    "preview": "var digits = { data: [[0.0, 0.0, 5.0, 13.0, 9.0, 1.0, 0.0, 0.0, 0.0, 0.0, 13.0, 15.0, 10.0, 15.0, 5.0, 0.0, 0.0, 3.0, 15"
  },
  {
    "path": "ml/datasets/out/iris_data.js",
    "chars": 3952,
    "preview": "var iris = { data: [[5.1, 3.5, 1.4, 0.2], [4.9, 3.0, 1.4, 0.2], [4.7, 3.2, 1.3, 0.2], [4.6, 3.1, 1.5, 0.2], [5.0, 3.6, 1"
  },
  {
    "path": "ml/decisiontree/decisiontree.js",
    "chars": 9075,
    "preview": "/**\n * Decision-Tree Learning\n */\n\n/* Tree Node */\nvar Node = function() {\n  this.init.apply(this, arguments);\n};\nNode.p"
  },
  {
    "path": "ml/gbdt/README.md",
    "chars": 828,
    "preview": "# Gradient Boosting Module\n\n## description\nGradient Boosting Decision Trees (GBDT) Learning \n\n## usage in JavaScript (ES"
  },
  {
    "path": "ml/gbdt/package.json",
    "chars": 743,
    "preview": "{\n  \"name\": \"gradient_boosting\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Gradient Boosting Regression Tree Module\",\n  \"m"
  },
  {
    "path": "ml/gbdt/src/boston_data.js",
    "chars": 40153,
    "preview": "export default {data: [[0.49298,0.0,9.9,0.0,0.544,6.635,82.5,3.3175,4.0,304.0,18.4,396.9,4.54],[3.56868,0.0,18.1,0.0,0.5"
  },
  {
    "path": "ml/gbdt/src/gradient_boosting.js",
    "chars": 2131,
    "preview": "/**\n * Gradient Boosting Regression Tree (GBRT) Module\n * @author https://github.com/wellflat\n */\n\nimport RegressionTree"
  },
  {
    "path": "ml/gbdt/src/index.js",
    "chars": 844,
    "preview": "import GradientBoostingRegressor from './gradient_boosting';\nimport boston from './boston_data';\nimport { rmse, score } "
  },
  {
    "path": "ml/gbdt/src/metrics.js",
    "chars": 1345,
    "preview": "/**\n * MSE (Mean Squared Error)\n * @param {number[]} test\n * @param {number[]} pred\n * @return {number}\n */\nexport funct"
  },
  {
    "path": "ml/gbdt/src/regression_tree.js",
    "chars": 4401,
    "preview": "export default class RegressionTree {\n    /**\n     * @param {number} depth \n     */\n    constructor(depth) {\n        /**"
  },
  {
    "path": "ml/kmeans/kmeans.js",
    "chars": 4972,
    "preview": "/**\n * provides routines for k-means clustering, generating code books,\n * and quantizing vectors by comparing them with"
  },
  {
    "path": "ml/logistic_regression/logistic_regression.ts",
    "chars": 3809,
    "preview": "module ml {\n    /**\n     * Logistic Regression class\n     */\n    export class LogisticRegression {\n\n        constructor"
  },
  {
    "path": "ml/logistic_regression/matrix.ts",
    "chars": 9540,
    "preview": "module ml {\n    /**\n     * Matrix class\n     */\n    export class Matrix {\n        public elements: number[][];\n\n       "
  },
  {
    "path": "ml/logistic_regression/vector.ts",
    "chars": 3348,
    "preview": "module ml {\n    /**\n     * Vector class\n     */\n    export class Vector {\n\n        constructor(public elements: number["
  },
  {
    "path": "ml/scw/README.md",
    "chars": 1940,
    "preview": "# SCW (Soft Confidence Weighted Learning)\n\n* SCW algorithm and LIBSVM format data loader modules  \n(JavaScript codes in "
  },
  {
    "path": "ml/scw/data_loader.ts",
    "chars": 3748,
    "preview": "/**\n * Data loader for LIBSVM data format\n * <label> <index1>:<value1> <index2>:<value2> ... \\n\n */\n\nimport * as fs from"
  },
  {
    "path": "ml/scw/out/app.js",
    "chars": 1146,
    "preview": "\"use strict\";\nvar scw_1 = require('./scw');\nvar data_loader_1 = require('./data_loader');\nvar featureSize = 123;\nvar eta"
  },
  {
    "path": "ml/scw/out/data_loader.js",
    "chars": 3803,
    "preview": "\"use strict\";\nvar fs = require('fs');\nvar readline = require('readline');\nvar DataLoader = (function () {\n    function D"
  },
  {
    "path": "ml/scw/out/scw.js",
    "chars": 5164,
    "preview": "\"use strict\";\nvar SCW = (function () {\n    function SCW(n, eta, C, type) {\n        if (type === void 0) { type = SCW.SCW"
  },
  {
    "path": "ml/scw/out/types.js",
    "chars": 47,
    "preview": "\"use strict\";\n//# sourceMappingURL=types.js.map"
  },
  {
    "path": "ml/scw/scw.ts",
    "chars": 5753,
    "preview": "/**\n * SCW (Soft Confidence Weighted Learning) class\n */\nexport class SCW {\n    public static SCW_I = 'scw_i';\n    publi"
  },
  {
    "path": "ml/scw/types.ts",
    "chars": 196,
    "preview": "/**\n * Shared types across multiple machine learning components.\n */\nexport type Feature = { index: number, value: numbe"
  },
  {
    "path": "ml/t-sne/.babelrc",
    "chars": 175,
    "preview": "{\n    \"presets\": [\n        [\n            \"@babel/preset-env\",\n            {\n                \"useBuiltIns\": \"usage\",\n    "
  },
  {
    "path": "ml/t-sne/.eslintrc.json",
    "chars": 395,
    "preview": "{\n    \"extends\": [\"eslint:recommended\"],\n    \"plugins\": [],\n    \"parserOptions\": {\n        \"sourceType\": \"module\",\n     "
  },
  {
    "path": "ml/t-sne/.gitignore",
    "chars": 11,
    "preview": "__tsne.js\r\n"
  },
  {
    "path": "ml/t-sne/README.md",
    "chars": 1209,
    "preview": "# t-SNE Module\n\n## description\n[t-SNE](https://en.wikipedia.org/wiki/T-distributed_stochastic_neighbor_embedding) (t-Dis"
  },
  {
    "path": "ml/t-sne/package.json",
    "chars": 669,
    "preview": "{\n  \"name\": \"t-sne\",\n  \"version\": \"1.0.0\",\n  \"description\": \"t-SNE JavaScript implementation\",\n  \"main\": \"dst\",\n  \"scrip"
  },
  {
    "path": "ml/t-sne/src/digits_data.js",
    "chars": 615444,
    "preview": "/* Digits Data Set\n *   http://scikit-learn.org/stable/auto_examples/datasets/plot_digits_last_image.html\n *   classes: "
  },
  {
    "path": "ml/t-sne/src/index.js",
    "chars": 504,
    "preview": "/**\n * t-SNE module usage, sample code\n */\n\nimport tSNE from './tsne';\nimport { digits } from './digits_data';\n\nconst pa"
  },
  {
    "path": "ml/t-sne/src/tsne.js",
    "chars": 10629,
    "preview": "\n/**\n * t-SNE Module\n * @author https://github.com/wellflat\n */\nimport { clone } from './utils';\n\nexport default class t"
  },
  {
    "path": "ml/t-sne/src/utils.js",
    "chars": 796,
    "preview": "\nimport { promises as fs } from 'fs';\n\n/**\n * clone 2d-typed array\n * @param {Float64Array[]} src\n * @return {Float64Arr"
  },
  {
    "path": "ml/utils/data_utils.ts",
    "chars": 1352,
    "preview": "function splitData(data: [number[][], number[]], testSize: number = 0.2): [number[][], number[]] {\n    var trainData: nu"
  },
  {
    "path": "ml/utils/metrics.ts",
    "chars": 3119,
    "preview": "module ml {\n    /**\n     * Classification metrics functions\n     */\n    export class Metrics {\n        static accuracy(l"
  },
  {
    "path": "ml/utils/preprocessing.ts",
    "chars": 2090,
    "preview": "module ml {\n    /**\n     * Data preprocessing class\n     */\n    export class Preprocessing {\n\n        // standardize da"
  }
]

About this extraction

This page contains the full source code of the wellflat/imageprocessing-labs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 125 files (2.2 MB), approximately 582.8k tokens, and a symbol index with 394 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!