├── .gitignore ├── third └── .gitignore ├── examples ├── console │ ├── .gitignore │ ├── init.js │ ├── console.html │ └── ScriptArea.class.js ├── plot │ ├── csv │ │ ├── ExampleId.csv │ │ ├── ExampleB.csv │ │ ├── ExampleA.csv │ │ ├── ExampleC.csv │ │ ├── ExampleC2.csv │ │ └── example-trigo.csv │ ├── images │ │ └── bird.jpg │ ├── plot.css │ └── plot-editor.js ├── gpu │ ├── benchmark.html │ ├── effect-designer.css │ ├── effect-designer.js │ ├── benchmark.js │ ├── effect-designer.html │ └── GLEffect.more.js ├── demo │ ├── demo.html │ └── demo.js ├── common │ ├── FileLoader-Webcam.ext.js │ ├── Webcam.html │ ├── video-loader.html │ ├── FileLoader.html │ ├── FileLoader.css │ ├── Webcam.class.js │ └── Shortcuts.object.js ├── gameoflife │ ├── gameoflife.html │ └── gameoflife.js ├── scripts │ ├── colorEnhancement.js │ └── testCanvas.js ├── imageViewer │ ├── demo.html │ ├── demo.css │ └── demo.js ├── illusion │ ├── illusion.html │ └── illusion.js ├── Disk.js ├── keypoints │ ├── keypoints.html │ └── keypoints.js ├── modes │ └── modes.html ├── base.css ├── sift │ ├── sift.html │ └── sift.js ├── colorenhancement │ ├── demo.js │ └── demo.html └── ppl │ └── ppl.html ├── index.html ├── .gitmodules ├── doc ├── content │ ├── categories.json │ └── readme.md ├── guides │ ├── sandbox │ │ └── README.md │ ├── tests │ │ └── README.md │ ├── eg-iframe.html │ ├── manipulation │ │ └── README.md │ └── functions │ │ └── README.md ├── tags │ ├── matlab_like.rb │ ├── fixme.rb │ └── todo.rb ├── guides.json └── jsduck.json ├── licence.txt ├── src ├── Matching │ ├── Matching.class.js │ └── Matching.Match.js ├── MatrixView │ └── MatrixView.informations.js └── Matrix │ ├── Matrix.elementary_math.complex_numbers.js │ └── Matrix.numeric_types.js ├── projects ├── wDenoising.js ├── colorInvariants.js └── drawHistogram.js ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /min/*.js 2 | /modules/*.js 3 | -------------------------------------------------------------------------------- /third/.gitignore: -------------------------------------------------------------------------------- 1 | canvas.js 2 | * 3 | 4 | -------------------------------------------------------------------------------- /examples/console/.gitignore: -------------------------------------------------------------------------------- 1 | *.*# 2 | *.*~ 3 | -------------------------------------------------------------------------------- /examples/plot/csv/ExampleId.csv: -------------------------------------------------------------------------------- 1 | 1 2 3 4 5 6 7 8 9 -------------------------------------------------------------------------------- /examples/plot/csv/ExampleB.csv: -------------------------------------------------------------------------------- 1 | 0 5 2 | 2 4 3 | 4 3 4 | 6 2 5 | 8 1 -------------------------------------------------------------------------------- /examples/plot/csv/ExampleA.csv: -------------------------------------------------------------------------------- 1 | 0.1 2 | 0.5 3 | 0.9 4 | 0.7 5 | 0.2 6 | -.3 7 | -.7 -------------------------------------------------------------------------------- /examples/plot/csv/ExampleC.csv: -------------------------------------------------------------------------------- 1 | -2 1. .0 2 | -1 .9 .4 3 | 0 .7 .7 4 | 1 .4 .9 5 | 2 .0 1. -------------------------------------------------------------------------------- /examples/plot/images/bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Etsitpab/JSM/HEAD/examples/plot/images/bird.jpg -------------------------------------------------------------------------------- /examples/plot/csv/ExampleC2.csv: -------------------------------------------------------------------------------- 1 | -2 -1. -.0 2 | -1 -.9 -.4 3 | 0 -.7 -.7 4 | 1 -.4 -.9 5 | 2 -.0 -1. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/Matrix3x3"] 2 | path = submodules/Matrix3x3 3 | url = https://github.com/Etsitpab/Matrix3x3 4 | [submodule "submodules/SuperCanvas"] 5 | path = submodules/SuperCanvas 6 | url = https://github.com/Etsitpab/SuperCanvas 7 | -------------------------------------------------------------------------------- /doc/content/categories.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Classes Documentation", 4 | "groups": [ 5 | { 6 | "name": "Main Classes", 7 | "classes": ["Matrix"] 8 | } 9 | ] 10 | } 11 | ] -------------------------------------------------------------------------------- /examples/plot/plot.css: -------------------------------------------------------------------------------- 1 | #uiLeft { 2 | display: inline-block; 3 | padding-top: 10px; 4 | width: 135px; 5 | float: left; 6 | } 7 | 8 | #uiRight { 9 | padding-top: 10px; 10 | width: 135px; 11 | float: right; 12 | } 13 | 14 | #image { 15 | width: calc(100% - 290px); 16 | } 17 | -------------------------------------------------------------------------------- /doc/guides/sandbox/README.md: -------------------------------------------------------------------------------- 1 | # Debug 2 | 3 | This is *not* a tutorial but a sandbox. 4 | 5 | 6 | ## Small console 7 | 8 | You can use this to execute JS code. 9 | The final value appear in the log. 10 | 11 | @example 12 | execute = function(field) { console.log(eval(field.value)) }; 13 | document.write('
'); 14 | document.write(''); 15 | document.write('
'); 16 | 17 | 18 | ## Other examples 19 | 20 | Provide some examples here... -------------------------------------------------------------------------------- /doc/guides/tests/README.md: -------------------------------------------------------------------------------- 1 | # Debug 2 | 3 | This is *not* a tutorial but a sandbox. 4 | 5 | 6 | ## Small console 7 | 8 | You can use this to execute JS code. 9 | The final value appear in the log. 10 | 11 | @example 12 | execute = function(field) { console.log(eval(field.value)) }; 13 | document.write('
'); 14 | document.write(''); 15 | document.write('
'); 16 | 17 | 18 | ## Other examples 19 | 20 | Provide some examples here... -------------------------------------------------------------------------------- /examples/gpu/benchmark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GPU Benchmark 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 | Drop an image... 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /doc/guides/eg-iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My Examples 6 | 7 | 8 | 9 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /doc/tags/matlab_like.rb: -------------------------------------------------------------------------------- 1 | # Tag: @todo 2 | # Parameter: title (on the first line), description (next lines) 3 | # Effect: 4 | # - display a 'ToDo' section in the documented function. 5 | 6 | require "jsduck/tag/boolean_tag" 7 | 8 | class Matlab_like < JsDuck::Tag::BooleanTag 9 | def initialize 10 | @pattern = "matlike" 11 | @signature = {:long => "Matlike", :short => "M"} 12 | @html_position = POS_DOC + 0.1 13 | @css = <<-EOCSS 14 | .signature .matlike { 15 | color: rgb(0, 95, 206); 16 | background-color: rgb(255, 255, 255); 17 | border: 1px solid rgb(213, 80, 0); 18 | } 19 | .matlike-box { 20 | border: 1px solid rgb(213, 80, 0); 21 | } 22 | EOCSS 23 | super 24 | end 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /examples/console/init.js: -------------------------------------------------------------------------------- 1 | /*global Dom, JsConsole, ScriptArea, OutTable, Plot, Disk, Matrix, console, document, FileReader, Tools*/ 2 | 3 | var plotA, plotB, canvas; 4 | window.addEventListener("load", function () { 5 | 'use strict'; 6 | canvas = new SuperCanvas(document.body); 7 | var size = [$('plot1Container').clientWidth - 20, $('plot1Container').clientHeight - 20] 8 | plotA = new Plot('plotA', size, 'plot1Container'); 9 | 10 | size = [$('plot2Container').clientWidth - 20, $('plot2Container').clientHeight - 20] 11 | plotB = new Plot('plotB', size, 'plot2Container'); 12 | $S("uiLeft").display = "none"; 13 | $S("imageSelector").display = "none"; 14 | $S("plot1Container").display = "none"; 15 | $S("plot2Container").display = "none"; 16 | }, false); 17 | -------------------------------------------------------------------------------- /doc/guides/manipulation/README.md: -------------------------------------------------------------------------------- 1 | # How to extract and set values in a Matrix 2 | 3 | First, we must create a `Matrix` with values inside. For instance, we can use the `randi` function. 4 | The command for extracting values from a `Matrix` is the command `select`. 5 | When executing the following codes, the result will be displayed in the console of the browser. 6 | It should open with the `F12` key. 7 | 8 | The simplest way to extract values is to specified along each dimension which indices must be retained. 9 | 10 | // Create a 5x5 Matrix containing integers between 1 and 9 11 | var A = Matrix.randi(9, 5).display("A"); 12 | 13 | // Extract the first column and the third row 14 | A.select(0).display("First column"); 15 | A.select([], 2).display(Third row"); 16 | 17 | # Basic 18 | -------------------------------------------------------------------------------- /doc/tags/fixme.rb: -------------------------------------------------------------------------------- 1 | # Tag: @fixme 2 | # Parameters: none 3 | # Effect: 4 | # - display a 'FixMe' flag in the doc. 5 | # - generate a warning during doc generation. 6 | 7 | require "jsduck/tag/boolean_tag" 8 | require "jsduck/logger" 9 | 10 | class FixMe < JsDuck::Tag::BooleanTag 11 | def initialize 12 | @pattern = "fixme" 13 | @signature = {:long => "Fix me", :short => "Fix"} 14 | @css = <<-EOCSS 15 | .signature .fixme { 16 | font-weight: bold; 17 | color: black; 18 | background-color: #F5D833; 19 | border: 3px double #AA0000; 20 | } 21 | .fixme-box { 22 | border: 3px double #AA0000; 23 | } 24 | EOCSS 25 | super 26 | end 27 | 28 | def parse_doc(p, pos) 29 | JsDuck::Logger.warn(nil, "@fixme found here", pos) 30 | super 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /licence.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | -------------------------------------------------------------------------------- /examples/demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/demo/demo.js: -------------------------------------------------------------------------------- 1 | /*global console, document, Matrix, Colorspaces, CIE, open */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | var image, canvas; 5 | 6 | function updateOutput(image, init) { 7 | "use strict"; 8 | canvas.displayImage(image, 0, init); 9 | drawImageHistogram("histogram", image); 10 | } 11 | 12 | window.onload = function () { 13 | "use strict"; 14 | var callback = function (evt) { 15 | var onread = function () { 16 | image = this.im2double() 17 | updateOutput(image, true); 18 | }; 19 | var im = new Image(); 20 | im.src = this; 21 | im.onload = function() { 22 | im.height = 50; 23 | im.style.marginRight = "3px"; 24 | $("images").appendChild(im); 25 | } 26 | im.onclick = function () { 27 | Matrix.imread(im.src, onread); 28 | } 29 | }; 30 | initFileUpload('loadFile', callback); 31 | canvas = new SuperCanvas(document.body); 32 | var fieldsets = initFieldset(); 33 | fieldsets.hideAll(); 34 | initInputs(); 35 | document.body.onresize = updateOutput; 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /examples/common/FileLoader-Webcam.ext.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, nomen: true */ 2 | /*global FileLoader, FileSlot, Webcam */ 3 | 4 | 5 | /** @class FileLoader */ 6 | 7 | /** Add available Webcams as new slots. 8 | * FileSlot.onload event is fired when the Webcam is ready to play. */ 9 | FileLoader.prototype.appendWebcams = function () { 10 | 'use strict'; 11 | var that = this; 12 | if (!Webcam) { 13 | return; 14 | } 15 | Webcam.forEach(function (cam) { 16 | var slot = that.createSlot('Camera: ' + cam.name, null, FileSlot.UNDELETABLE); 17 | slot.type = 'webcam'; 18 | slot.name = cam.name; 19 | cam.onready = function () { 20 | slot.setVideoThumbnail(cam.videoElement, null, FileSlot.UNDELETABLE); 21 | cam.onready = function () { 22 | slot._dataLoaded(cam.videoElement); 23 | }; 24 | cam.onready(); 25 | }; 26 | slot.onchange = function (select) { 27 | if (select) { 28 | cam.start(); 29 | } else { 30 | slot.data = null; 31 | cam.stop(); 32 | } 33 | }; 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /examples/common/Webcam.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webcam 6 | 7 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Matching/Matching.class.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /** @class Matching 20 | * This class provides tools for image comparison with SIFT-like 21 | * local descriptors. 22 | * @singleton 23 | */ 24 | var Matching = {}; 25 | 26 | if (typeof window === 'undefined') { 27 | var JSM = require('../modules/JSM.js'); 28 | var Matrix = JSM.Matrix; 29 | var Tools = JSM.Tools; 30 | module.exports.Matching = Matching; 31 | } 32 | -------------------------------------------------------------------------------- /examples/gameoflife/gameoflife.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/common/video-loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Video Loader 6 | 7 | 8 | 9 | 10 | 32 | 38 | 39 | 40 |
41 | File loader not supported 42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /doc/tags/todo.rb: -------------------------------------------------------------------------------- 1 | # Tag: @todo 2 | # Parameter: title (on the first line), description (next lines) 3 | # Effect: 4 | # - display a 'ToDo' section in the documented function. 5 | 6 | require "jsduck/tag/boolean_tag" 7 | 8 | class ToDo < JsDuck::Tag::BooleanTag 9 | def initialize 10 | @pattern = "todo" 11 | @signature = {:long => "To do", :short => "do"} 12 | @html_position = POS_DOC + 0.1 13 | @css = <<-EOCSS 14 | .signature .todo { 15 | color: black; 16 | background-color: #F5D833; 17 | border: 1px solid #FD6B1B; 18 | } 19 | .todo-box { 20 | border: 1px solid #FD6B1B; 21 | } 22 | EOCSS 23 | super 24 | end 25 | 26 | def parse_doc(p, pos) 27 | h = { :tagname => @tagname, :title => p.match(/^.*$/), :doc => :multiline } 28 | return h; 29 | end 30 | 31 | def process_doc(h, tags, pos) 32 | h[@tagname] = { :title => tags[0][:title], :doc => tags[0][:doc] }; 33 | end 34 | 35 | def format(context, formatter) 36 | context[@tagname][:doc] = formatter.format(context[@tagname][:doc]) 37 | end 38 | 39 | def to_html(context) 40 | content = context[@tagname] 41 | if content[:title].empty? 42 | title = 'There is work to be done!' 43 | else 44 | title = 'Work to be done: ' + content[:title] 45 | end 46 | <<-EOHTML 47 |
48 |

#{title}

49 | #{content[:doc]} 50 |
51 | EOHTML 52 | end 53 | end 54 | 55 | -------------------------------------------------------------------------------- /examples/common/FileLoader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | File Loader 6 | 7 | 8 | 35 | 41 | 42 | 43 |
44 | File loader not supported 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /examples/scripts/colorEnhancement.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 4 | var JSM = require('../../modules/JSM.js'); 5 | 6 | 7 | GLOBAL.Matrix = JSM.Matrix; 8 | GLOBAL.Tools = JSM.Tools; 9 | require('../../modules/Image.js'); 10 | require("../../projects/colorEnhancement.js"); 11 | 12 | 13 | var src = "/home/mazin/Images/NZ - 2015/koalichat/GOPR1899.JPG"; 14 | Matrix.imread(src, function () { 15 | var scales; 16 | console.log("Read !"); 17 | var space = "Opponent", channel = 0; 18 | this.imwrite("00 - original.jpg"); 19 | var image = Matrix.applycform(this.im2double(), "RGB to " + space); 20 | if (!scales) { 21 | Tools.tic(); 22 | scales = image.get([], [], channel).computeScaleSpace(); 23 | console.log("Scalespace time", Tools.toc()); 24 | } 25 | var bin = 2048; 26 | USE_CST = false; 27 | var w = 0.01, 28 | gamma = 0.5, 29 | alpha = 0.0, 30 | nIter = 1, 31 | K = Infinity; 32 | Tools.tic(); 33 | var lut = getLUT(K, w, gamma, [bin, bin], nIter); 34 | console.log("LUT time", Tools.toc()); 35 | console.log("gamma =", gamma, "w = ", w, "alpha", alpha, "nIter", nIter, "bin", bin, "USE_CST", USE_CST); 36 | 37 | var out = Matrix.gaussianColorEnhancementLUT(scales, lut, alpha); 38 | out = image.set([], [], channel, out).applycform(space + " to RGB"); 39 | out.imwrite("01 - output.jpg"); 40 | out["-="](out.min())["/="](out.max()); 41 | out.imwrite("01 - output_norm.jpg"); 42 | }); 43 | // console.log(JSM); 44 | -------------------------------------------------------------------------------- /doc/guides.json: -------------------------------------------------------------------------------- 1 | [ 2 | /*{ 3 | "title": "Units tests", 4 | "items": [ 5 | { 6 | "name": "tests", 7 | "title": "MatrixView Tests", 8 | "description": "Check that everthing is right." 9 | } 10 | ] 11 | },*/ 12 | { 13 | "title": "Tutorials", 14 | "items": [ 15 | { 16 | "name": "getting_started", 17 | "title": "The Matrix class introduction", 18 | "description": "This introduction presents the basics of the Matrix class." 19 | }, 20 | { 21 | "name": "views", 22 | "title": "The MatrixView class introduction", 23 | "description": "This guide presents how to use the MatrixView and the iterators to manipulate datas." 24 | }, 25 | { 26 | "name": "functions", 27 | "title": "An ordered presentation of functions", 28 | "description": "This guide presents the mains functions ordered by categories." 29 | }/*, 30 | { 31 | "name": "manipulation", 32 | "title": "Presentation of the manipulation functions", 33 | "description": "This guide introduces the many way to play with Matrix content." 34 | }, 35 | { 36 | "title": "Subgroup...", 37 | "items": [] 38 | }, 39 | { 40 | "name": "sandbox", 41 | "title": "Sandbox", 42 | "description": "Useful for quick testing." 43 | }*/ 44 | ] 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /examples/imageViewer/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 | 26 | 28 |
29 | 30 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/illusion/illusion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Color illusion 10 | 11 | 12 | 13 | 14 |
15 |

Color Illusion

16 | 17 |
18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | Instructions 32 |

33 | Upload an image, click on the start button and look at the black point at the center of the picture. 34 | After some time, you should see the color image you uploaded. 35 | This is in fact a black and white version of your picture. 36 |

37 |

38 | 39 |
40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/Disk.js: -------------------------------------------------------------------------------- 1 | var Disk = { 2 | "exist": function (key) { 3 | 'use strict'; 4 | if (typeof key !== 'string') { 5 | throw new Error('Disk: key must be a string.'); 6 | } 7 | return localStorage.hasOwnProperty(key); 8 | }, 9 | "save": function (key, file, force) { 10 | 'use strict'; 11 | force = force || false; 12 | if (!force && this.exist(key)) { 13 | throw new Error('Disk: Key already exist.'); 14 | } else { 15 | localStorage.setItem(key, file); 16 | } 17 | return this; 18 | }, 19 | "load": function (key) { 20 | 'use strict'; 21 | if (this.exist(key)) { 22 | var a = localStorage.getItem(key); 23 | return a; 24 | } 25 | throw new Error('Disk: Key doesn\'t exist.'); 26 | }, 27 | "remove": function (key) { 28 | 'use strict'; 29 | if (this.exist(key) !== undefined) { 30 | localStorage.removeItem(key); 31 | } else { 32 | throw new Error('Disk: Key doesn\'t exist.'); 33 | } 34 | }, 35 | "getItemList": function (mask) { 36 | 'use strict'; 37 | if (mask !== undefined && typeof mask !== 'string') { 38 | throw new Error('Disk: Mask must be a string.'); 39 | } 40 | var i, out = []; 41 | for (i in localStorage) { 42 | if (localStorage.hasOwnProperty(i)) { 43 | if (mask === undefined || i.match(mask)) { 44 | out.push(i); 45 | } 46 | } 47 | } 48 | return out.sort(); 49 | }, 50 | "clear": function () { 51 | 'use strict'; 52 | localStorage.clear(); 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /src/MatrixView/MatrixView.informations.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /** @class MatrixView */ 20 | 21 | (function (MatrixView, MatrixView_prototype) { 22 | 'use strict'; 23 | 24 | /** Returns the number of array dimensions. 25 | * It is a Matlab alias for {@link MatrixView#getDimLength}, 26 | * 27 | * @return {Number} 28 | */ 29 | MatrixView_prototype.ndims = function () { 30 | return this.getDimLength(); 31 | }; 32 | 33 | /** Test if a the view corresponds to a row vector or not. 34 | * 35 | * @return{Boolean} 36 | */ 37 | MatrixView_prototype.isrow = function () { 38 | var size = this.getSize(); 39 | return (size.length === 2 && size[0] === 1); 40 | }; 41 | 42 | /** Test if the view correponds to a column vector or not. 43 | * 44 | * @return{Boolean}. 45 | */ 46 | MatrixView_prototype.iscolumn = function () { 47 | var size = this.getSize(); 48 | return (size.length === 2 && size[1] === 1); 49 | }; 50 | 51 | /** Test if the view corresponds to a vector or not. 52 | * 53 | * @return{Boolean} 54 | */ 55 | MatrixView_prototype.isvector = function () { 56 | var size = this.getSize(); 57 | return (size.length === 2 && (size[1] === 1 || size[0] === 1)); 58 | }; 59 | 60 | /** Test if the view corresponds to a matrix or not. 61 | * 62 | * @return{Boolean} 63 | */ 64 | MatrixView_prototype.ismatrix = function () { 65 | return this.getSize().length === 2; 66 | }; 67 | 68 | })(MatrixView, MatrixView.prototype); 69 | -------------------------------------------------------------------------------- /doc/jsduck.json: -------------------------------------------------------------------------------- 1 | { 2 | // "--import": [1.0, 1.1], 3 | // "--new-since": 1.1, 4 | "--title": "JSM Documentation", 5 | "--message": "Have a look at the tutorials!", 6 | "--welcome": "content/readme.md", 7 | 8 | "--guides": "guides.json", 9 | "--eg-iframe": "guides/eg-iframe.html", 10 | // "--tests": true, 11 | //"--categories": "content/categories.json", 12 | "--tags": ["tags/fixme.rb", "tags/todo.rb", "tags/matlab_like.rb"], 13 | 14 | "--output": "html", 15 | 16 | "--external": ["Integer", "Matrix", "MatrixView", "Image", 17 | "Float32Array", "Uint8ClampedArray", 18 | "HTMLCanvasElement"], 19 | "--": [ 20 | "../src/Tools/Tools.js", 21 | 22 | "../src/MatrixView/MatrixView.class.js", 23 | "../src/MatrixView/MatrixView.informations.js", 24 | "../src/MatrixView/MatrixView.manipulation.js", 25 | 26 | "../src/Matrix/Matrix.class.js", 27 | "../src/Matrix/Matrix.Tools.js", 28 | "../src/Matrix/Matrix.informations.js", 29 | "../src/Matrix/Matrix.manipulation.js", 30 | "../src/Matrix/Matrix.numeric_types.js", 31 | "../src/Matrix/Matrix.construction.js", 32 | "../src/Matrix/Matrix.operators.js", 33 | "../src/Matrix/Matrix.elementary_math.complex_numbers.js", 34 | "../src/Matrix/Matrix.statistics.base.js", 35 | 36 | "../src/Matrix/Matrix.extend.elementary_math.special_functions.js", 37 | "../src/Matrix/Matrix.extend.histograms.js", 38 | 39 | "../src/Linalg/Linalg.class.js", 40 | 41 | "../src/Image/Image.class.js", 42 | "../src/Image/Image.color.js", 43 | "../src/Image/Image.fourier.js", 44 | "../src/Image/Image.wavelets.js", 45 | 46 | "../src/Matching/Matching.class.js", 47 | "../src/Matching/Matching.Match.js", 48 | "../src/Matching/Matching.Descriptor.js", 49 | "../src/Matching/Matching.DescriptorData.js", 50 | "../src/Matching/Matching.Keypoint.js", 51 | "../src/Matching/Matching.Scalespace.js", 52 | "../src/Matching/Matching.Sift.js", 53 | 54 | "../projects/CIE.js", 55 | "../projects/CIE.data.js", 56 | "../src/Plot/Plot.class.js" 57 | // "../src/Matrix/Matrix.statistics.base.js", 58 | // "../src/Matrix/Matrix.elementary_math.special_functions.js", 59 | // "../src/Matrix/Matrix.Matlab.js" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /projects/wDenoising.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | (function () { 20 | 'use strict'; 21 | 22 | var processCoeffsHard = function (D, t) { 23 | for (var i = 0, ei = D.length; i < ei; i++) { 24 | if ((D[i] > 0 ? D[i] : -D[i]) < t) { 25 | D[i] = 0; 26 | } 27 | } 28 | return D; 29 | }; 30 | 31 | Matrix.prototype.wdenoise = function (t, name) { 32 | // Default parameters 33 | var out = Matrix.zeros(this.size()); 34 | var J = Matrix.dwtmaxlev([this.size(0), this.size(1)], name); 35 | for (var c = 0; c < this.size(2); c++) { 36 | var channel = this.get([], [], c); 37 | var wt = Matrix.wavedec2(channel, J, name); 38 | for (var j = J - 1; j >= 0; j--) { 39 | var d = wt[0].getData(); 40 | var sb = wt[1].value([0, 0]) * wt[1].value([0, 1]); 41 | processCoeffsHard(d.subarray(sb, 4 * sb), t); 42 | wt = Matrix.upwlev2(wt, name); 43 | } 44 | channel = wt[0].reshape(wt[1].get(0).getData()); 45 | out.set([], [], c, channel); 46 | } 47 | return out; 48 | }; 49 | 50 | Matrix.prototype.wdenoiseRAW = function (t, name) { 51 | // Default parameters 52 | var J = Matrix.dwtmaxlev([this.size(0), this.size(1)], name); 53 | var wt = Matrix.wavedec2(this, J, name); 54 | for (var j = J - 1; j >= 0; j--) { 55 | var d = wt[0].getData(); 56 | var sb = wt[1].value([0, 0]) * wt[1].value([0, 1]); 57 | processCoeffsHard(d.subarray(sb, 4 * sb), t); 58 | wt = Matrix.upwlev2(wt, name); 59 | } 60 | return wt[0].reshape(wt[1].get(0).getData()); 61 | }; 62 | })(); 63 | -------------------------------------------------------------------------------- /examples/plot/csv/example-trigo.csv: -------------------------------------------------------------------------------- 1 | -3.1416 -1.2246e-16 -1 1.2246e-16 1 2 | -3.0416 -0.099833 -0.995 0.099833 0.995 3 | -2.9416 -0.19867 -0.98007 0.19867 0.98007 4 | -2.8416 -0.29552 -0.95534 0.29552 0.95534 5 | -2.7416 -0.38942 -0.92106 0.38942 0.92106 6 | -2.6416 -0.47943 -0.87758 0.47943 0.87758 7 | -2.5416 -0.56464 -0.82534 0.56464 0.82534 8 | -2.4416 -0.64422 -0.76484 0.64422 0.76484 9 | -2.3416 -0.71736 -0.69671 0.71736 0.69671 10 | -2.2416 -0.78333 -0.62161 0.78333 0.62161 11 | -2.1416 -0.84147 -0.5403 0.84147 0.5403 12 | -2.0416 -0.89121 -0.4536 0.89121 0.4536 13 | -1.9416 -0.93204 -0.36236 0.93204 0.36236 14 | -1.8416 -0.96356 -0.2675 0.96356 0.2675 15 | -1.7416 -0.98545 -0.16997 0.98545 0.16997 16 | -1.6416 -0.99749 -0.070737 0.99749 0.070737 17 | -1.5416 -0.99957 0.0292 0.99957 -0.0292 18 | -1.4416 -0.99166 0.12884 0.99166 -0.12884 19 | -1.3416 -0.97385 0.2272 0.97385 -0.2272 20 | -1.2416 -0.9463 0.32329 0.9463 -0.32329 21 | -1.1416 -0.9093 0.41615 0.9093 -0.41615 22 | -1.0416 -0.86321 0.50485 0.86321 -0.50485 23 | -0.94159 -0.8085 0.5885 0.8085 -0.5885 24 | -0.84159 -0.74571 0.66628 0.74571 -0.66628 25 | -0.74159 -0.67546 0.73739 0.67546 -0.73739 26 | -0.64159 -0.59847 0.80114 0.59847 -0.80114 27 | -0.54159 -0.5155 0.85689 0.5155 -0.85689 28 | -0.44159 -0.42738 0.90407 0.42738 -0.90407 29 | -0.34159 -0.33499 0.94222 0.33499 -0.94222 30 | -0.24159 -0.23925 0.97096 0.23925 -0.97096 31 | -0.14159 -0.14112 0.98999 0.14112 -0.98999 32 | -0.041593 -0.041581 0.99914 0.041581 -0.99914 33 | 0.058407 0.058374 0.99829 -0.058374 -0.99829 34 | 0.15841 0.15775 0.98748 -0.15775 -0.98748 35 | 0.25841 0.25554 0.9668 -0.25554 -0.9668 36 | 0.35841 0.35078 0.93646 -0.35078 -0.93646 37 | 0.45841 0.44252 0.89676 -0.44252 -0.89676 38 | 0.55841 0.52984 0.8481 -0.52984 -0.8481 39 | 0.65841 0.61186 0.79097 -0.61186 -0.79097 40 | 0.75841 0.68777 0.72593 -0.68777 -0.72593 41 | 0.85841 0.7568 0.65364 -0.7568 -0.65364 42 | 0.95841 0.81828 0.57482 -0.81828 -0.57482 43 | 1.0584 0.87158 0.49026 -0.87158 -0.49026 44 | 1.1584 0.91617 0.4008 -0.91617 -0.4008 45 | 1.2584 0.9516 0.30733 -0.9516 -0.30733 46 | 1.3584 0.97753 0.2108 -0.97753 -0.2108 47 | 1.4584 0.99369 0.11215 -0.99369 -0.11215 48 | 1.5584 0.99992 0.012389 -0.99992 -0.012389 49 | 1.6584 0.99616 -0.087499 -0.99616 0.087499 50 | 1.7584 0.98245 -0.18651 -0.98245 0.18651 51 | 1.8584 0.95892 -0.28366 -0.95892 0.28366 52 | 1.9584 0.92581 -0.37798 -0.92581 0.37798 53 | 2.0584 0.88345 -0.46852 -0.88345 0.46852 54 | 2.1584 0.83227 -0.55437 -0.83227 0.55437 55 | 2.2584 0.77276 -0.63469 -0.77276 0.63469 56 | 2.3584 0.70554 -0.70867 -0.70554 0.70867 57 | 2.4584 0.63127 -0.77557 -0.63127 0.77557 58 | 2.5584 0.55069 -0.83471 -0.55069 0.83471 59 | 2.6584 0.4646 -0.88552 -0.4646 0.88552 60 | 2.7584 0.37388 -0.92748 -0.37388 0.92748 61 | 2.8584 0.27942 -0.96017 -0.27942 0.96017 62 | 2.9584 0.18216 -0.98327 -0.18216 0.98327 63 | 3.0584 0.083089 -0.99654 -0.083089 0.99654 64 | -------------------------------------------------------------------------------- /examples/illusion/illusion.js: -------------------------------------------------------------------------------- 1 | /*global window, console, document, Matrix, Colorspaces, CIE, open, $, $F */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | var IMAGE, IMC, IMG, TIMER; 5 | function updateOutput(image) { 6 | "use strict"; 7 | var outputCanvas = $("outputImage"); 8 | var div = $("image"); 9 | var canvasXSize = div.offsetWidth; 10 | var canvasYSize = div.offsetHeight; 11 | outputCanvas.width = canvasXSize; 12 | outputCanvas.height = canvasYSize; 13 | image.imshow(outputCanvas, "fit"); 14 | outputCanvas.style.marginTop = (div.offsetHeight - outputCanvas.height) / 2; 15 | } 16 | 17 | function exportImage() { 18 | "use strict"; 19 | var outputCanvas = $("outputImage"); 20 | open(outputCanvas.toDataURL()); 21 | } 22 | 23 | window.onload = function () { 24 | "use strict"; 25 | var inputs = document.getElementsByTagName('input'); 26 | var focus = function () { 27 | this.focus(); 28 | }; 29 | var i; 30 | for (i = 0; i < inputs.length; i++) { 31 | if (inputs[i].type == 'range') { 32 | inputs[i].addEventListener('click', focus); 33 | } 34 | } 35 | 36 | var onread = function () { 37 | IMAGE = this.im2double(); 38 | updateOutput(IMAGE); 39 | IMC = IMAGE.getCopy() 40 | .applycform("RGB to CMY") 41 | .applycform("RGB to Ohta") 42 | .set([], [], 0, 0.5) 43 | .applycform("Ohta to RGB"); 44 | IMG = IMAGE.rgb2gray(2); 45 | }; 46 | 47 | var run = function () { 48 | if (TIMER) { 49 | window.clearTimeout(TIMER); 50 | } 51 | updateOutput(IMC["-"](0.5)[".*"]($F("contrast"))["+"]($F("luminosity"))); 52 | var canvas = $('outputImage'); 53 | var context = canvas.getContext('2d'); 54 | context.beginPath(); 55 | context.arc(canvas.width / 2, canvas.height / 2, 5, 0, 2 * Math.PI, false); 56 | context.fillStyle = 'black'; 57 | context.fill(); 58 | 59 | var f = function () { 60 | updateOutput(IMG); 61 | }; 62 | TIMER = window.setTimeout(f, $F("time") * 1000); 63 | }; 64 | $("start").addEventListener("click", run); 65 | $("export").addEventListener("click", exportImage); 66 | 67 | var read = function (evt) { 68 | 69 | var callback = function (evt) { 70 | Matrix.imread(this, onread); 71 | }; 72 | 73 | // Only call the handler if 1 or more files was dropped. 74 | if (this.files.length) { 75 | var i; 76 | for (i = 0; i < this.files.length; i++) { 77 | window.readFile(this.files[i], callback, "url"); 78 | } 79 | } 80 | 81 | }; 82 | $("loadFile").addEventListener("change", read, false); 83 | 84 | var fieldsets = initFieldset(); 85 | fieldsets.hideAll(); 86 | //Matrix.imread("castle.jpg", onread); 87 | 88 | }; 89 | -------------------------------------------------------------------------------- /src/Matching/Matching.Match.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | var root = typeof window === 'undefined' ? module.exports : window; 20 | 21 | ////////////////////////////////////////////////////////////////// 22 | // Match Class // 23 | ////////////////////////////////////////////////////////////////// 24 | 25 | 26 | (function (global) { 27 | 28 | /** This class provides object to store matches. 29 | * 30 | * @class Matching.Match 31 | * @param {Integer} num_1 32 | * Number of the first `Keypoint`. 33 | * 34 | * @param {Object} key_1 35 | * The first `Keypoint`. 36 | * 37 | * @param {Integer} num_2 38 | * Number of the second `Keypoint`. 39 | * 40 | * @param {Integer} key_2 41 | * The second `Keypoint`. 42 | * 43 | * @param {Number} distance 44 | * The distance between the two keypoints. 45 | * 46 | * @constructor 47 | */ 48 | function Match(i, k1, j, k2, d) { 49 | /** First keypoint */ 50 | this.k1 = k1; 51 | /* The first keypoint number for localisation in scalespace */ 52 | this.k1.number = i; 53 | /** First keypoint */ 54 | this.k2 = k2; 55 | /* The second keypoint number for localisation in scalespace */ 56 | this.k2.number = j; 57 | /** The disimilarity measure between these two keypoints */ 58 | this.distance = d; 59 | } 60 | 61 | Match.prototype.isValid = false; 62 | 63 | /** Function used to sort the matches. 64 | * @property 65 | */ 66 | Match.compar = function (m1, m2) { 67 | return m1.distance - m2.distance; 68 | }; 69 | 70 | /** Convert a match to a String. Function used for export purpose. 71 | */ 72 | Match.prototype.toString = function () { 73 | var str = this.k1.toString(true, 74 | true, false, false) + " "; 75 | str += this.k2.toString(true, true, false, false) + " "; 76 | str += this.distance; 77 | str += " " + (this.isValid ? 1 : 0); 78 | return str; 79 | }; 80 | 81 | global.Match = Match; 82 | 83 | })(Matching); 84 | -------------------------------------------------------------------------------- /examples/gpu/effect-designer.css: -------------------------------------------------------------------------------- 1 | optgroup:empty { 2 | display: none; 3 | } 4 | 5 | input, select { 6 | padding: 2px; 7 | } 8 | 9 | input[type=button] { 10 | padding-left: 1em; 11 | padding-right: 1em; 12 | } 13 | 14 | #menu input[type=text], 15 | #menu select { 16 | min-width: 11em; 17 | max-width: 90%; 18 | } 19 | 20 | #menu select { 21 | max-height: 20em; 22 | } 23 | 24 | #outputs > p, 25 | #outputs > ul { 26 | margin: 1em; 27 | } 28 | 29 | .bold { 30 | font-weight: bold; 31 | } 32 | 33 | .italic { 34 | font-style: italic; 35 | } 36 | 37 | .small { 38 | font-size: 0.8em; 39 | } 40 | 41 | .narrow { 42 | padding-left: 0.5em !important; 43 | padding-right: 0.5em !important; 44 | } 45 | 46 | .error { 47 | color: darkred; 48 | } 49 | 50 | .error::first-line { 51 | font-weight: bold; 52 | } 53 | 54 | .disabled-effect { 55 | color: gray; 56 | } 57 | 58 | .param-button { 59 | position:relative; 60 | left:-3.5em; 61 | opacity: 0.3; 62 | background-color: transparent; 63 | } 64 | 65 | .param-button:hover { 66 | opacity: 1; 67 | } 68 | 69 | #help-button { 70 | margin-left: 1em; 71 | margin-right: 1em; 72 | } 73 | 74 | 75 | /* Boxes format */ 76 | 77 | body { 78 | background-color: #fafafa; 79 | margin: 0px; 80 | padding: 0px; 81 | overflow-x: hidden; 82 | overflow-y: auto; 83 | } 84 | 85 | body > div { 86 | background-color: white; 87 | margin: 6px; 88 | padding: 3px; 89 | border: 1px solid gray; 90 | } 91 | 92 | #editor { 93 | display: none; 94 | } 95 | 96 | #outputs:empty::after { 97 | content: 'Nothing to be displayed :('; 98 | display: block; 99 | margin: 1em; 100 | } 101 | 102 | #footer { 103 | background-color: transparent; 104 | border-color: lightgray; 105 | color: gray; 106 | text-align: center; 107 | } 108 | 109 | 110 | /* Movile vs. desktop (481+ and 768+) */ 111 | 112 | @media only all and (max-width: 481px) { 113 | 114 | body > div { 115 | margin: 2px !important; 116 | } 117 | 118 | #resizer { 119 | display: none; 120 | } 121 | 122 | #menu { 123 | width: 100% !important; 124 | } 125 | 126 | } 127 | 128 | @media only all and (min-width: 480px) { 129 | 130 | #menu { 131 | top: 0px; 132 | bottom: 0px; 133 | z-index: +1; 134 | } 135 | 136 | #resizer { 137 | position: absolute; 138 | width: 4px; 139 | right: 0px; 140 | top: 0px; 141 | bottom: 0px; 142 | background-color: #ddd; 143 | /* border: 1px solid orange; */ 144 | } 145 | 146 | #resizer:hover { 147 | cursor: e-resize; 148 | background-color: #aaa; 149 | } 150 | 151 | .left-column { 152 | position: fixed; 153 | overflow-x: hidden; 154 | overflow-y: auto; 155 | left: 0px; 156 | width: 180px; 157 | } 158 | 159 | .right-column { 160 | overflow-x: auto; 161 | margin-left: 200px; /* = left-column-width + 2 * (margin + padding + border) */ 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /examples/imageViewer/demo.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #000; 3 | font-size: 11px; 4 | font-family: "Open Sans", Helvetica, Arial, sans-serif; 5 | margin: 0px; 6 | margin-top: 0px; 7 | height: 100%; 8 | z-index: -1; 9 | } 10 | 11 | input, select, fieldset, file { 12 | font-size: inherit; 13 | font-family: inherit; 14 | border-radius: 3px; 15 | border: 1px solid #e6e6e6; 16 | } 17 | 18 | fieldset { 19 | padding-left: 6px; 20 | padding-right: 6px; 21 | } 22 | 23 | input[type=button]:hover { 24 | background-color: silver; 25 | } 26 | 27 | input[type=button], [type=file], select { 28 | background-color: #e6e6e6; 29 | } 30 | 31 | input[type=button], [type=text], [type=range], [type=file], label, select { 32 | color: black; 33 | display: inline-block; 34 | width: 100%; 35 | margin-bottom: 2px; 36 | margin-left: 0px; 37 | } 38 | 39 | input[type=text] { 40 | text-align:right; 41 | } 42 | 43 | .parameter { 44 | display: flex; 45 | flex-flow: row nowrap; 46 | align-items: center; 47 | } 48 | 49 | .parameter > div { 50 | flex: 1 0; 51 | } 52 | .parameter > input[type=range] { 53 | flex: 1; 54 | } 55 | .parameter > input[type=button] { 56 | flex: 1; 57 | margin: 1px; 58 | } 59 | 60 | label.val { 61 | width: 20px; 62 | display: inline-block; 63 | vertical-align: middle; 64 | } 65 | input[type=range].val { 66 | width: calc(70% - 6px - 20px); 67 | vertical-align: middle; 68 | margin-right: 0px; 69 | } 70 | input[type=text].val { 71 | width: 30%; 72 | vertical-align: middle; 73 | } 74 | 75 | input[type=range].val2 { 76 | width: calc(70% - 3px); 77 | vertical-align: middle; 78 | margin-right: 0px; 79 | } 80 | input[type=text].val2 { 81 | width: 30%; 82 | vertical-align: middle; 83 | } 84 | 85 | 86 | p { 87 | margin-top: 5px; 88 | margin-bottom: 0px; 89 | text-align: justify; 90 | } 91 | 92 | #ui { 93 | border-radius: 3px; 94 | background-color: #BBB; 95 | padding: 10px; 96 | top: 10px; 97 | left: 10px; 98 | width: 170px; 99 | height: auto; 100 | position: fixed; 101 | } 102 | 103 | #interface { 104 | display: block; 105 | width: 100%; 106 | height: calc(100% - 75px); 107 | } 108 | 109 | #log { 110 | font-size: inherit; 111 | font-family: monospace; 112 | border-radius: 3px; 113 | border: 1px solid #e6e6e6; 114 | 115 | margin: 5px; 116 | width: 100%; 117 | height: 100px; 118 | overflow: auto; 119 | margin-bottom: 2px; 120 | margin-left: 0px; 121 | } 122 | 123 | #outputImage { 124 | image-rendering: pixelated; 125 | position: absolute; 126 | z-index: 0; 127 | } 128 | 129 | hr { 130 | } 131 | 132 | #help { 133 | font-size: 14px; 134 | display: none; 135 | position: fixed; 136 | top: 15%; 137 | left: 15%; 138 | width: 70%; 139 | height: 70%; 140 | border: 15px solid #e6e6e6; 141 | padding: 10px; 142 | margin: 10px; 143 | border-radius: 5px; 144 | background-color: #FFF; 145 | box-shadow: 0px 0px 200px 24px rgba(100, 100, 100, 0.5); 146 | overflow: auto; 147 | } -------------------------------------------------------------------------------- /examples/common/FileLoader.css: -------------------------------------------------------------------------------- 1 | /* Slot formating */ 2 | 3 | .js-fileslot { 4 | display: inline-block; 5 | overflow: hidden; 6 | position: relative; /* required for delete button positioning */ 7 | margin: 5px; /* overwritten in js-fileslot-selected */ 8 | min-width: 80px; 9 | width: 180px; 10 | height: 120px; 11 | line-height: 120px; 12 | text-align: center; 13 | vertical-align: middle; 14 | } 15 | 16 | .js-fileslot:hover { 17 | cursor: pointer; 18 | } 19 | 20 | .js-fileslot .jsfs-delete-button { 21 | cursor: default; 22 | position: absolute; 23 | border: none; 24 | margin: 0px; 25 | top: 1px; 26 | right: 3px; 27 | width: 21px; 28 | height: 21px; 29 | background-repeat: no-repeat; 30 | background-position: center; 31 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAQAAADs3AYjAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBwoPBSy20ue1AAACRklEQVQoz12TT0iTARyG3337vm/ft32KSJqptBoEYk6iKOiSS6MQRBQPeSzoGB696KGDXSOwDtUtDGcgRnmoQ2ZCSsg6aFGWi/6CspgO/6zp3NPFYvY7vfA+vKfnJxXdYncqvplcz2VyW8nV+Ifu4s73N3xtrx14Ff2klFIqqEZVqtWp+VR/+HExrnTfW67TQQQXE4sgB+nkLgts9BVha71v6KAcAwc/AfwIA4ca+pmB3l2M2CythDCxsfHjw8LBxcaHQweLbMQkSb8nuyhBOISJYCJcRBl1OIgQl0hPSqL5CaWIEPsYYZgmbFwq6OEB53Dx4fGC7WbtDF7ExEVEyZFngmYOcI0MWW5jYmPSRn5QS4lKDESQKu4BG0xxm+9Akk4C2AQ4RCahdxlRggjip4E7FIBlYJbLuIQI4OExlzEynqmsTGVlaUHjWpVUqU1NaVQF+WRIKtM3zwisG8rLFZIO67w85SX5FFa9/CrI0I4MWet6n9iPi41FhPvkgNc8osAWwzQSIIRDDYsJIzB9UgVtydURdSmvZ7qlG3oqqUUt8gk5OqrqaTM81nb1pVBeSxrXloY0IVc3lVZEKzKEXDXJHJP0cfICDhZBTtCAhYlHiGOcpYpSgrSyMClJSsWeU4+DsDDxE8LDj42HhcdpRtiO/bPnITFcDCxsLFxKsbGp4AxDZHqLRPvVN0oPdQRxCOJhE+Q4Vxhnre8/w9PtywOJ6Bf90JIMlatajYrOV/SX7zV8d7c7G/+cnMnN5VaSa/Gfe37mD3STfLWdAVBVAAAAAElFTkSuQmCC); 32 | } 33 | 34 | 35 | /* Slot types / borders */ 36 | 37 | .js-fileslot-dragover { 38 | border: 2px dashed gray; 39 | } 40 | 41 | .js-fileslot-ghost { 42 | border: 2px dotted lightgray; 43 | } 44 | 45 | .js-fileslot-ghost::after { 46 | content: '+'; 47 | font-weight: bold; 48 | font-size: 2em; 49 | } 50 | 51 | .js-fileslot-loading { 52 | border: 1px solid blue; 53 | } 54 | 55 | .js-fileslot-loading::after { 56 | content: '...'; 57 | font-weight: bold; 58 | } 59 | 60 | .js-fileslot-error { 61 | border: 1px solid red; 62 | } 63 | 64 | .js-fileslot-error::after { 65 | content: '!'; 66 | font-weight: bold; 67 | } 68 | 69 | .js-fileslot-invalid { 70 | border: 1px solid red; 71 | font-style: italic; 72 | } 73 | 74 | .js-fileslot-unknown { 75 | border: 1px solid lightgray; 76 | } 77 | 78 | 79 | /* Format slot content */ 80 | 81 | .js-fileslot * { 82 | vertical-align: middle; 83 | } 84 | 85 | .js-fileslot-T-image { 86 | width: auto; 87 | } 88 | 89 | .js-fileslot-T-text { 90 | border: 1px solid black; 91 | } 92 | 93 | .js-fileslot-T-text pre { 94 | overflow: hidden; 95 | font-size: 0.5em; 96 | margin: 3px; 97 | width: 100%; 98 | height: 100%; 99 | text-align: left; 100 | line-height: normal; 101 | font-family: "Courier New", Courier, monospace; 102 | } 103 | 104 | 105 | /* Last: overwriting other properties */ 106 | 107 | .js-fileslot-selected { 108 | border: 3px solid limegreen; 109 | margin: 2px; /* overwrite fl-slot margin */ 110 | } 111 | -------------------------------------------------------------------------------- /examples/keypoints/keypoints.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Keypoints Detection 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 |
28 |
29 | Scalespace 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 |
39 | 40 |
41 | Keypoints detection 42 | 43 | 44 | 45 | 46 | 47 | 51 |
52 | 53 |
54 | 55 |
56 | Image View 57 | 58 | 59 | 60 | 61 | 62 | 63 | 71 | 76 |
77 | 78 |
79 | 80 |
81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /examples/console/console.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 |
74 |
75 |
76 |
77 |
78 | 79 | 80 | -------------------------------------------------------------------------------- /examples/modes/modes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

A contrario modes detection

23 | 24 |
25 | 26 |
27 | 28 |
29 | Histogram properties 30 | 31 | 32 | 33 | 34 | 38 |
39 | 40 | 41 |
42 | 43 |
44 | Add points 45 | 46 | 47 | 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | 57 | 58 |
59 | 60 |
61 | View 62 | 63 | 64 | 68 | 69 | 70 | 75 | 76 | 77 | 83 | 84 | 86 |
87 | 88 | 89 |
90 | 91 |
92 | 93 |
94 | 95 |
96 | 97 |
98 | 99 |
100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /examples/gpu/effect-designer.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, nomen: true, plusplus: true, browser: true */ 2 | /*global Shortcuts, FileLoader, FileSlot, Effects, GLEffect */ 3 | 4 | // Create the shortcuts 5 | function createShortcuts() { 6 | 'use strict'; 7 | // Shortcuts.create(document); 8 | Shortcuts.create('sourceCode', 'Escape', function () { Effects.stopEditing(); }); 9 | Shortcuts.create('sourceCode', 'Ctrl+Enter', function () { Effects.fromHTML(); }); 10 | Shortcuts.create('effects', 'Delete', function () { Effects.remove(); }); 11 | Shortcuts.create('effects', 'Escape', function () { Effects.stopEditing(); }); 12 | Shortcuts.create('effects', 'Ctrl+Shift+Arrowup', function () { Effects.move(-1, true); }); 13 | Shortcuts.create('effects', 'Ctrl+Shift+ArrowDown', function () { Effects.move(+1, true); }); 14 | Shortcuts.create('effects', 'Ctrl+Shift+PageUp', function () { Effects.move(0, false); }); 15 | Shortcuts.create('effects', 'Ctrl+Shift+PageDown', function () { Effects.move(-1, false); }); 16 | Shortcuts.create('parameter', 'Enter', function () { Effects.updateParameter(); }); 17 | } 18 | 19 | // Create the file loader 20 | function createFileLoader() { 21 | 'use strict'; 22 | var nloaded = 0; 23 | var fl = new FileLoader('images', FileLoader.MULTIPLE, 'image/*,video/*'); 24 | fl.appendWebcams(); 25 | fl.onchange = function (slot, nowSelected) { 26 | if (!nowSelected || slot.type !== 'webcam') { 27 | Effects.run(fl); 28 | } 29 | }; 30 | fl.onload = function (slot) { 31 | if (slot.type === 'webcam') { 32 | Effects.run(fl); 33 | } else if (nloaded++ === 0 && fl.isSelectionEmpty()) { 34 | slot.select(); 35 | } 36 | }; 37 | 38 | // Load output image when double-clicked 39 | var canvas = GLEffect._getDefaultContext().canvas; 40 | canvas.addEventListener('dblclick', function () { 41 | var inputs = Effects._getInputs(); 42 | if (inputs) { 43 | var image = Effects._runOnce(inputs, true); 44 | var slot = fl.createSlot(null, 'js-fileloader-loading'); 45 | FileSlot.Loader.image.call(slot, image.toCanvas().toDataURL()); 46 | } 47 | }); 48 | } 49 | 50 | // Allow the left column to be resized 51 | function makeColumnResizable() { 52 | 'use strict'; 53 | var resizer = document.getElementById('resizer'); 54 | var leftBox = document.getElementsByClassName('left-column')[0]; 55 | var rightBoxes = [].slice.call(document.getElementsByClassName('right-column')); 56 | var getIntStyle = function (elmt, property) { 57 | return parseInt(window.getComputedStyle(elmt).getPropertyValue(property), 10); 58 | }; 59 | var space = getIntStyle(rightBoxes[0], 'margin-left') - getIntStyle(leftBox, 'width'); 60 | // Set mouse listener 61 | var offset = null; 62 | resizer.addEventListener('mousedown', function (evt) { 63 | evt.preventDefault(); 64 | offset = getIntStyle(leftBox, 'width') - evt.clientX; 65 | }); 66 | document.addEventListener('mousemove', function (evt) { 67 | if (offset !== null) { 68 | leftBox.style.width = (evt.clientX + offset) + 'px'; 69 | } 70 | }); 71 | document.addEventListener('mouseup', function (evt) { 72 | if (offset !== null) { 73 | var width = evt.clientX + offset, margin = width + space; 74 | offset = null; 75 | leftBox.style.width = width + 'px'; 76 | rightBoxes.forEach(function (box) { 77 | box.style.marginLeft = margin + 'px'; 78 | }); 79 | } 80 | }); 81 | } 82 | 83 | // Initialize the interface 84 | function init() { 85 | 'use strict'; 86 | createShortcuts(); 87 | createFileLoader(); 88 | makeColumnResizable(); 89 | Effects.loadSampleList(); 90 | Effects.loadReductionList(); 91 | } 92 | 93 | -------------------------------------------------------------------------------- /examples/scripts/testCanvas.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | var JSM = require('../../modules/JSM.js'); 4 | GLOBAL.Matrix = JSM.Matrix; 5 | GLOBAL.MatrixView = JSM.MatrixView; 6 | GLOBAL.Tools = JSM.Tools; 7 | 8 | require('../../modules/Image.js'); 9 | */ 10 | var fs = require('fs'), 11 | Canvas = require('canvas'), 12 | Image = Canvas.Image; 13 | 14 | var src = process.argv[2]; 15 | /* 16 | var write = function (canvas, name) { 17 | var data = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height) 18 | // console.log(data.constructor); 19 | // data = new Uint8ClampedArray(data); 20 | // data = canvas.getContext('2d').createImageData(canvas.width, canvas.height); 21 | var canvasOut = new Canvas(canvas.width, canvas.height); 22 | canvasOut.getContext('2d').putImageData(data, 0, 0); 23 | 24 | var out = fs.createWriteStream(name), 25 | stream = canvasOut.syncJPEGStream(); 26 | stream.on('data', function (chunk) { 27 | console.log("Write chunk for ", name) 28 | out.write(chunk); 29 | }); 30 | stream.on('end', function () { 31 | console.log("End stream for", name) 32 | }); 33 | };*/ 34 | /*var write2 = function (data, width, height, name) { 35 | var canvasOut = new Canvas(width, height); 36 | canvasOut.getContext('2d').putImageData(data, 0, 0); 37 | 38 | var out = fs.createWriteStream(name), 39 | stream = canvasOut.syncJPEGStream(); 40 | stream.on('data', function (chunk) { 41 | console.log("Write chunk for", name) 42 | out.write(chunk); 43 | }); 44 | stream.on('end', function () { 45 | console.log("End stream for", name) 46 | }); 47 | }; 48 | */ 49 | /* 50 | (function () { 51 | "use strict"; 52 | var write = function (canvasOut, name) { 53 | var out = fs.createWriteStream(name), 54 | stream = canvasOut.syncJPEGStream(); 55 | stream.on('data', function (chunk) { 56 | console.log("Write chunk for", name) 57 | out.write(chunk); 58 | }); 59 | stream.on('end', function () { 60 | console.log("End stream for", name) 61 | }); 62 | }; 63 | write(new Canvas(500, 500), "out11.jpg"); 64 | write(new Canvas(500, 500), "out21.jpg"); 65 | })();*/ 66 | 67 | (function () { 68 | "use strict"; 69 | var out, stream; 70 | out = fs.createWriteStream("test1.jpg"); 71 | stream = new Canvas(500, 500).syncJPEGStream(); 72 | stream.on('data', function (chunk) { 73 | console.log("Write chunk for", "test1.jpg") 74 | out.write(chunk); 75 | }); 76 | stream.on('end', function () { 77 | console.log("End stream for", "test1.jpg") 78 | }); 79 | out = fs.createWriteStream("test2.jpg"); 80 | stream = new Canvas(500, 500).syncJPEGStream(); 81 | stream.on('data', function (chunk) { 82 | console.log("Write chunk for", "test2.jpg") 83 | out.write(chunk); 84 | }); 85 | stream.on('end', function () { 86 | console.log("End stream for", "test2.jpg") 87 | }); 88 | })(); 89 | 90 | /* 91 | Matrix.imread(src, function () { 92 | // var data = this.getImageData(), 93 | var width = this.size(1), height = this.size(0); 94 | data = new Canvas(width, height).getContext('2d').createImageData(width, height); 95 | 96 | write2(data, width, height, "out11.jpg"); 97 | write2(data, width, height, "out21.jpg"); 98 | // this.imwrite("out1.jpg"); 99 | // this.imwrite("out2.jpg"); 100 | }); 101 | 102 | fs.readFile(src, function (err, data) { 103 | if (err) { 104 | throw err; 105 | } 106 | var img = new Image(); 107 | img.src = data; 108 | var width = img.width, height = img.height; 109 | var canvasIn = new Canvas(width, height); 110 | var ctx = canvasIn.getContext('2d'); 111 | ctx.drawImage(img, 0, 0, img.width, img.height); 112 | var data = canvasIn.getContext('2d').getImageData(0, 0, width, height); 113 | 114 | write2(data, width, height, "out12.jpg"); 115 | write2(data, width, height, "out22.jpg"); 116 | // write(canvasIn, 'out1.jpg'); 117 | // write(canvasIn, 'out2.jpg'); 118 | }); 119 | */ 120 | -------------------------------------------------------------------------------- /examples/base.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-size: 11px; 3 | font-family: "Open Sans", Helvetica, Arial, sans-serif; 4 | background-color: #2E2E2E; 5 | margin: 0px; 6 | margin-top: 0px; 7 | height: 100%; 8 | } 9 | 10 | input, select, fieldset, file { 11 | font-size: inherit; 12 | font-family: inherit; 13 | border-radius: 3px; 14 | border: 1px solid #e6e6e6; 15 | } 16 | 17 | fieldset { 18 | padding-left: 6px; 19 | padding-right: 6px; 20 | } 21 | 22 | input[type=button]:hover { 23 | background-color: silver; 24 | } 25 | 26 | input[type=button], [type=file], select { 27 | background-color: #e6e6e6; 28 | } 29 | 30 | input[type=button], [type=text], [type=range], [type=file], label, select { 31 | color: black; 32 | display: inline-block; 33 | width: 100%; 34 | margin-bottom: 2px; 35 | margin-left: 0px; 36 | } 37 | 38 | input[type=text] { 39 | text-align:right; 40 | } 41 | 42 | .parameter { 43 | display: flex; 44 | flex-flow: row nowrap; 45 | align-items: center; 46 | } 47 | 48 | .parameter > div { 49 | flex: 1 0; 50 | } 51 | .parameter > input[type=range] { 52 | flex: 1; 53 | } 54 | .parameter > input[type=button] { 55 | flex: 1; 56 | margin: 1px; 57 | } 58 | 59 | label.val { 60 | width: 20px; 61 | display: inline-block; 62 | vertical-align: middle; 63 | } 64 | input[type=range].val { 65 | width: calc(70% - 6px - 20px); 66 | vertical-align: middle; 67 | margin-right: 0px; 68 | } 69 | input[type=text].val { 70 | width: 30%; 71 | vertical-align: middle; 72 | } 73 | 74 | input[type=range].val2 { 75 | width: calc(70% - 3px); 76 | vertical-align: middle; 77 | margin-right: 0px; 78 | } 79 | input[type=text].val2 { 80 | width: 30%; 81 | vertical-align: middle; 82 | } 83 | 84 | 85 | p { 86 | margin-top: 5px; 87 | margin-bottom: 0px; 88 | text-align: justify; 89 | } 90 | 91 | #log { 92 | font-size: inherit; 93 | font-family: monospace; 94 | border-radius: 3px; 95 | border: 1px solid #e6e6e6; 96 | 97 | margin: 5px; 98 | width: 100%; 99 | height: 100px; 100 | overflow: auto; 101 | margin-bottom: 2px; 102 | margin-left: 0px; 103 | } 104 | 105 | #outputImage { 106 | padding-left: 0; 107 | padding-right: 0; 108 | } 109 | 110 | h1 { 111 | margin-top: 0px; 112 | } 113 | 114 | hr { 115 | } 116 | 117 | #help { 118 | font-size: 14px; 119 | display: none; 120 | position: fixed; 121 | top: 7%; 122 | left: 15%; 123 | width: 70%; 124 | height: 70%; 125 | border: 15px solid #e6e6e6; 126 | padding: 10px; 127 | margin: 10px; 128 | border-radius: 5px; 129 | background-color: #FFF; 130 | box-shadow: 0px 0px 200px 24px rgba(100, 100, 100, 0.5); 131 | overflow: auto; 132 | } 133 | 134 | #images { 135 | display: block; 136 | height: 50px; 137 | border: 1px solid #e6e6e6; 138 | padding: 3px; 139 | margin-top: 7px; 140 | border-radius: 3px; 141 | } 142 | 143 | #imageSelector { 144 | border-radius: 3px; 145 | background-color: #BBB; 146 | padding: 10px; 147 | top: 10px; 148 | left: 10px; 149 | width: auto; 150 | height: auto; 151 | position: fixed; 152 | display: inline-block; 153 | } 154 | 155 | #ui, #uiLeft { 156 | border-radius: 3px; 157 | background-color: #BBB; 158 | padding: 10px; 159 | top: 130px; 160 | left: 10px; 161 | width: 170px; 162 | height: auto; 163 | position: fixed; 164 | display: inline-block; 165 | } 166 | 167 | #uiRight { 168 | border-radius: 3px; 169 | background-color: #BBB; 170 | padding: 10px; 171 | top: 10px; 172 | right: 10px; 173 | width: 170px; 174 | height: auto; 175 | position: fixed; 176 | display: inline-block; 177 | } 178 | 179 | 180 | .plot { 181 | border-radius: 3px; 182 | background-color: #BBB; 183 | padding: 10px; 184 | 185 | width: 360px; 186 | height: 270px; 187 | position: fixed; 188 | } 189 | 190 | #plot1Container { 191 | top:10px; 192 | right:10px; 193 | } 194 | 195 | #plot2Container { 196 | top:310px; 197 | right:10px; 198 | } 199 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Get core, functions and extensions from a DIR variable 2 | CLASSES = $(wildcard $(DIR)/*.class.js) 3 | EXTENDS = $(wildcard $(DIR)/*.extend*.js) 4 | MODULES = ${filter-out $(CLASSES) $(EXTENDS), $(wildcard $(DIR)/*.js)} 5 | 6 | # Add here files to add at the 'matrix.js' file 7 | SRC_DIR = src 8 | 9 | # Flags for uglifyjs 10 | UGLIFLAGS = -m --lint 11 | 12 | # Directory, list and concatenation of modules 13 | MOD_DIR = modules/ 14 | MOD_FILES = ${filter-out $(JSM), $(wildcard $(MOD_DIR)/*.js)} 15 | JSM = $(MOD_DIR)/JSM.js 16 | 17 | # Minified modules and projects 18 | MIN_DIR = min/ 19 | MIN_FILES = ${filter-out $(JSM_MIN), $(wildcard $(MIN_DIR)/*.js)} 20 | JSM_MIN = $(MIN_DIR)/JSM.min.js 21 | SRC_PROJECTS = $(wildcard projects/*.js) 22 | 23 | # Directory for HTML documentation 24 | DOC_DIR = doc/html 25 | 26 | # Licence header 27 | LIC_HEAD = licence.txt 28 | 29 | all: clean Matching Image Linalg Plot JSM projects 30 | 31 | Tools: $(TOOLS_FILES) 32 | $(eval DIR := $(SRC_DIR)/$@) 33 | $(eval NAME := $(MOD_DIR)/$@.js) 34 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 35 | @echo "* Module "$@" creation"; \ 36 | mkdir -p $(MOD_DIR); \ 37 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 38 | 39 | MatrixView: Tools 40 | $(eval DIR := $(SRC_DIR)/$@) 41 | $(eval NAME := $(MOD_DIR)/$@.js) 42 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 43 | @echo "* Module "$@" creation"; \ 44 | mkdir -p $(MOD_DIR); \ 45 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 46 | 47 | 48 | Matrix: MatrixView Tools 49 | $(eval DIR := $(SRC_DIR)/$@) 50 | $(eval NAME := $(MOD_DIR)/$@.js) 51 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 52 | @echo "* Module "$@" creation"; \ 53 | mkdir -p $(MOD_DIR); \ 54 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 55 | 56 | Image: Matrix 57 | $(eval DIR := $(SRC_DIR)/$@) 58 | $(eval NAME := $(MOD_DIR)/$@.js) 59 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 60 | @echo "* Module "$@" creation"; \ 61 | mkdir -p $(MOD_DIR); \ 62 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 63 | 64 | Linalg: Matrix 65 | $(eval DIR := $(SRC_DIR)/$@) 66 | $(eval NAME := $(MOD_DIR)/$@.js) 67 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 68 | @echo "* Module "$@" creation"; \ 69 | mkdir -p $(MOD_DIR); \ 70 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 71 | 72 | Matching: Matrix 73 | $(eval DIR := $(SRC_DIR)/$@) 74 | $(eval NAME := $(MOD_DIR)/$@.js) 75 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 76 | @echo "* Module "$@" creation"; \ 77 | mkdir -p $(MOD_DIR); \ 78 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 79 | 80 | Plot: 81 | $(eval DIR := $(SRC_DIR)/$@) 82 | $(eval NAME := $(MOD_DIR)/$@.js) 83 | $(eval NAME_MIN := $(MIN_DIR)/$@.min.js) 84 | @echo "* Module "$@" creation"; \ 85 | mkdir -p $(MOD_DIR); \ 86 | cat $(CLASSES) $(MODULES) $(EXTENDS) > $(NAME); \ 87 | 88 | # Node export 89 | JSM: Matrix 90 | @echo "* Concatenate ALL the minified JS code"; \ 91 | mkdir -p $(MOD_DIR); \ 92 | cat $(MOD_DIR)/Tools.js $(MOD_DIR)/MatrixView.js $(MOD_DIR)/Matrix.js > $(JSM); \ 93 | 94 | 95 | # Minify modules 96 | minify: $(wildcard $(MOD_DIR)/*.js) 97 | @mkdir -p $(MIN_DIR); \ 98 | for i in $?; do \ 99 | echo "* Minify module "`basename $$i`; \ 100 | min=`basename $$i .js`; \ 101 | name=$(MIN_DIR)/$${min}.min.js; \ 102 | cat $(LIC_HEAD) > $$name; \ 103 | uglifyjs $$i $(UGLIFLAGS) >> $$name; \ 104 | done; 105 | 106 | # Minify projects file 107 | projects: $(SRC_PROJECTS) 108 | @echo "* Minify projects"; 109 | @mkdir -p $(MIN_DIR); \ 110 | for i in $(SRC_PROJECTS); do \ 111 | min=`basename $$i .js`; \ 112 | name=$(MIN_DIR)/$${min}.min.js; \ 113 | cat $(LIC_HEAD) > $$name; \ 114 | uglifyjs $$i $(UGLIFLAGS) >> $$name; \ 115 | done; 116 | 117 | # Compile the documentation 118 | doc: 119 | @echo "* Create the documentation"; 120 | @cd doc; jsduck; cd .. \ 121 | 122 | # Execute jshint on the files 123 | lint: 124 | @echo "* Lint all the js files"; 125 | for i in $(SRC); do \ 126 | jshint $$i -c; \ 127 | done; \ 128 | for i in $(SRC_PROJECTS); do \ 129 | jshint $$i -c; \ 130 | done; 131 | 132 | clean: 133 | @echo "* Cleaning "; 134 | @rm -rf $(MIN_DIR)/*.js $(MOD_DIR)/*.js $(DOC_DIR)/*; 135 | 136 | .PHONY: clean projects doc 137 | -------------------------------------------------------------------------------- /projects/colorInvariants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /*global Matrix, Colorspaces */ 20 | Matrix.prototype.getColorInvariant = function (invariant, sigma) { 21 | 'use strict'; 22 | if (this.getSize(2) < 3) { 23 | throw new Error('Matrix.getColorInvariant: Image must have at least 3 channels.'); 24 | } 25 | sigma = sigma || 2; 26 | 27 | var RGBE = [ 28 | [0.3, 0.58, 0.11], 29 | [0.25, 0.25, -0.5], 30 | [0.5, -0.5, 0] 31 | ]; 32 | 33 | RGBE = [ 34 | [0.06, 0.63, 0.27], 35 | [0.30, 0.04, -0.35], 36 | [0.34, -0.60, 0.17] 37 | ]; 38 | 39 | RGBE = [ 40 | [0.33, 0.34, 0.33], 41 | [0.5, 0.0, -0.5], 42 | [0.25, -0.5, 0.25] 43 | ]; 44 | 45 | var im2RGBE = Colorspaces.getConversionFunction(RGBE); 46 | var imE = this.applycform(im2RGBE); 47 | var imEp = imE.gaussianGradient(sigma); 48 | imE = imE.gaussian(sigma); 49 | var E = imE.select([], [], [0]); 50 | var El = imE.select([], [], [1]); 51 | var Ell = imE.select([], [], [2]); 52 | 53 | var Ex = imEp.x.select([], [], [0]), Ey = imEp.y.select([], [], [0]); 54 | var Elx = imEp.x.select([], [], [1]), Ely = imEp.y.select([], [], [1]); 55 | var Ellx = imEp.x.select([], [], [2]), Elly = imEp.y.select([], [], [2]); 56 | 57 | var im, x, y; 58 | var E2; 59 | if (invariant === 'H') { 60 | im = El['./'](Ell); 61 | var EL2PELL2 = El[".^"](2)['+'](Ell[".^"](2)); 62 | x = Ell['.*'](Elx)['-'](El['.*'](Ellx))['./'](EL2PELL2); 63 | y = Ell['.*'](Ely)['-'](El['.*'](Elly))['./'](EL2PELL2); 64 | } else if (invariant === 'Cl') { 65 | im = El['./'](E); 66 | E2 = E[".^"](2); 67 | x = Elx['.*'](E)['-'](El['.*'](Ex))['./'](E2); 68 | y = Ely['.*'](E)['-'](El['.*'](Ey))['./'](E2); 69 | } else if (invariant === 'Cll') { 70 | im = Ell['./'](E); 71 | E2 = E[".^"](2); 72 | x = Ellx['.*'](E)['-'](Ell['.*'](Ex))['./'](E[".^"](2)); 73 | y = Elly['.*'](E)['-'](Ell['.*'](Ey))['./'](E[".^"](2)); 74 | } else if (invariant === 'W') { 75 | x = Ex['./'](E); 76 | y = Ey['./'](E); 77 | } else if (invariant === 'Wl') { 78 | x = Elx['./'](E); 79 | y = Ely['./'](E); 80 | } else if (invariant === 'Wll') { 81 | x = Ellx['./'](E); 82 | y = Elly['./'](E); 83 | } else if (invariant === 'Nl') { 84 | E2 = E[".^"](2); 85 | x = Elx['.*'](E)['-'](El['.*'](Ex))['./'](E2); 86 | y = Ely['.*'](E)['-'](El['.*'](Ey))['./'](E2); 87 | } else if (invariant === 'Nll') { 88 | E2 = E[".^"](2); 89 | var El2 = El[".^"](2), E3 = E[".^"](3); 90 | x = Ellx['.*'](E2)['-'](Ell['.*'](Ex['.*'](E)))['-'](Elx['.*'](El)['.*'](E)['.*'](2))['+'](El2['.*'](Ex)['.*'](2))['./'](E3); 91 | y = Elly['.*'](E2)['-'](Ell['.*'](Ey['.*'](E)))['-'](Ely['.*'](El)['.*'](E)['.*'](2))['+'](El2['.*'](Ey)['.*'](2))['./'](E3); 92 | } else { 93 | throw new Error('Matrix.getColorInvariant: Unknown Invariant ' + invariant); 94 | } 95 | 96 | var cplx = Matrix.complex(x, y); 97 | 98 | var phase = cplx.angle(); 99 | phase = phase["./"](Math.PI); 100 | var PI0 = phase["<"](0); 101 | phase = phase.set(PI0, phase.select(PI0)["+"](1)); 102 | 103 | return {im: im, x: x, y: y, norm: cplx.abs(), phase: phase}; 104 | }; 105 | -------------------------------------------------------------------------------- /doc/content/readme.md: -------------------------------------------------------------------------------- 1 | # A short presentation of the project: the Matrix class 2 | 3 | This class intends to provide an easy way to deal with nd-array. 4 | The Matrix name is in fact a bit simplistic since it refers to 2d array only while here a Matrix object is an nd-array. 5 | It intends to provide tools to deal with numerical data. 6 | The inspiration is the well known [Matlab][1] software though there are some differences in the syntax we used. 7 | 8 | [1]:http://www.mathworks.fr/products/matlab/ 9 | 10 | # Demos 11 | 12 | Here are some demos that have been realized with this project: 13 | 14 | - [Image editor](http://etsitpab.github.io/JSM/JSM/examples/colorspaces/colorspaces.html) 15 | - [Game of life](http://etsitpab.github.io/JSM/JSM/examples/gameoflife/gameoflife.html) 16 | - [Plot editor](http://etsitpab.github.io/JSM/JSM/examples/colorspaces/colorspaces.html) 17 | - [Keypoint detector](http://etsitpab.github.io/JSM/JSM/examples/keypoints/keypoints.html) 18 | - [Color constancy basic algorithms](http://etsitpab.github.io/JSM/JSM/examples/colorconstancy/colorconstancy.html) 19 | - [Illuminant estimations with projections on the planckian locus](http://etsitpab.github.io/JSM/JSM/examples/ppl/ppl.html) 20 | - [Image matching](http://etsitpab.github.io/JSM/JSM/examples/sift/sift.html) 21 | - [Histogram mode detection](http://etsitpab.github.io/JSM/JSM/examples/modes/modes.html) 22 | 23 | 24 | # Why develop a JavaScript numerical computing library ? 25 | 26 | Many reasons can justify this. First, JavaScript is fun. It's easy too use and it has very powerful features (closures, prototype, ...). 27 | Also, put it together with HTML and CSS and you have a perfect team to build great and very efficient UIs. 28 | For research purpose, it allows to make online demonstrations which can be used directly in the browser. 29 | 30 | More and more web applications request to deal with numerical data, and we do not found a library providing a complete and robust JavaScript framework to do it. 31 | 32 | # Other JavaScript libraries for numerical computation 33 | 34 | Here comes a list made of JS library that we found interesting. 35 | This list does not pretend to exhaustive and if you would like to see a link to your website added here please send an email. 36 | 37 | - [jStat](https://github.com/jstat/jstat) 38 | - [jsmat](https://github.com/ghewgill/jsmat) 39 | - [JSNum](https://github.com/kms15/jsnum) 40 | - [Numeric JavaScript](http://numericjs.com/numeric/documentation.html) 41 | - [Sylvester](http://sylvester.jcoglan.com/) 42 | - [jsfeat](http://inspirit.github.io/jsfeat/) 43 | 44 | # Content of the JSM project 45 | 46 | ./ 47 | +- doc/ 48 | | + Makefile - generate the documentation 49 | | + jsduck.json - doc. configuration file 50 | | + guides.json - tutorials configuration file 51 | | +- html/ - generated documentation (HTML format) 52 | | | + index.html - main page of the documentation 53 | | +- content/ - doc. content (raw) 54 | | | + readme.md - content of the doc. main page 55 | | | + categories.json - sort documented JS classes into categories 56 | | +- tag/ - custom tags definitions 57 | +- examples/ - examples of use of the Matrix class 58 | +- min/ - minify versions of the Matrix class and related 59 | | + matrix.js - standalone source file, containing all the JS code for the Matrix class 60 | | + matrix_min.js - same as matrix.js but minified 61 | | + _min.js - projects files minified 62 | +- projects/ - projects making use of the Matrix class 63 | +- src/ - source files 64 | | +- Matrix - Matrix JavaScript class, split into several files 65 | | +- MatrixView - MatrixView JavaScript class, split into several files 66 | | +- Tools - Tools JavaScript object, split into several files 67 | +- third/ - used to store third part projects 68 | + licence.txt - short licence description, included in JS files 69 | + Makefile - Makefile used to generate documentation, minified files and lint 70 | -------------------------------------------------------------------------------- /examples/imageViewer/demo.js: -------------------------------------------------------------------------------- 1 | /*global console, document, Matrix, Colorspaces, CIE, open */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | var path = "mypath", 5 | imagePrefixes = [ 6 | "image1", 7 | "image2", 8 | "image3", 9 | "image4" 10 | ], 11 | referenceImagesPath = ""; 12 | 13 | var IMAGES, SC; 14 | 15 | var parameters = { 16 | 'parameter1': ["0.7", "0.8", "0.9", "1.0", "1.1"], 17 | 'parameter2': ["0.7", "0.8", "0.9", "1.0", "1.1"], 18 | 'parameter3': ["0.2", "0.3", "0.4", "0.5", "0.6"], 19 | 'parameter4': ["0.2", "0.3", "0.4", "0.5", "0.6"], 20 | 'parameter5': ["0.5", "0.75", "1.0", "1.25", "1.5"] 21 | }; 22 | var parameterNames = { 23 | 'parameter1': "name1", 24 | 'parameter2': "name2", 25 | 'parameter3': "name3", 26 | 'parameter4': "name4", 27 | 'parameter5': "name5" 28 | } 29 | 30 | var currentParameterIndices = {}; 31 | 32 | function updateImage(name) { 33 | "use strict"; 34 | if (typeof name !== "string") { 35 | name = path + $("imagePrefix").value; 36 | 37 | for (var p in parameters) { 38 | name += "_" + parameterNames[p] + parameters[p][currentParameterIndices[p]]; 39 | } 40 | //name += "_0000.jpg"; 41 | name += ".jpg"; 42 | } 43 | console.log(name); 44 | var image = new Image(); 45 | image.onload = function () { 46 | SC.displayImage(this, 0, SC.matrix === undefined ? true : false); 47 | }; 48 | image.src = name; 49 | window.image = image; 50 | return; 51 | } 52 | 53 | 54 | var initParameters = function () { 55 | "use strict"; 56 | for (var p in imagePrefixes) { 57 | addOption($("imagePrefix"), imagePrefixes[p], imagePrefixes[p]); 58 | } 59 | $("imagePrefix").addEventListener("change", updateImage); 60 | 61 | var onChange = function () { 62 | currentParameterIndices[this.id] = this.value; 63 | console.log(parameters[this.id][this.value]); 64 | $(this.id + "Val").value = parameters[this.id][this.value]; 65 | $("currentTuning").value = JSON.stringify(currentParameterIndices); 66 | updateImage(); 67 | }; 68 | for (var p in parameters) { 69 | var label = document.createElement("label"); 70 | label.innerHTML = p; 71 | $("ui").appendChild(label); 72 | 73 | var range = document.createElement("input"); 74 | range.type = "range"; 75 | range.id = p 76 | range.min = 0; 77 | range.max = parameters[p].length - 1; 78 | range.value = Math.floor((parameters[p].length - 1) / 2); 79 | range.className = "val2"; 80 | range.type = "range"; 81 | range.addEventListener("change", onChange); 82 | $("ui").appendChild(range); 83 | 84 | var text = document.createElement("input"); 85 | text.id = p + "Val"; 86 | text.value = parameters[p][range.value]; 87 | text.className = "val2"; 88 | text.type = "text"; 89 | $("ui").appendChild(text); 90 | 91 | currentParameterIndices[p] = 0; 92 | } 93 | $("currentTuning").value = JSON.stringify(currentParameterIndices); 94 | 95 | $("saveTuning").addEventListener("click", function () { 96 | var value = JSON.stringify(currentParameterIndices); 97 | var name = $V("tuningName"); 98 | addOption($("bestTunings"), value, name); 99 | }); 100 | $("bestTunings").addEventListener("change", function () { 101 | currentParameterIndices = JSON.parse(this.value); 102 | for (var p in parameters) { 103 | $(p).value = parseInt(currentParameterIndices[p]); 104 | $(p + "Val").value = parameters[p][currentParameterIndices[p]]; 105 | } 106 | updateImage(); 107 | }); 108 | document.addEventListener("keydown", function (e) { 109 | if (e.keyCode === 82) { 110 | console.log("Down"); 111 | updateImage(referenceImagesPath + $("imagePrefix").value + ".JPG"); 112 | } 113 | }); 114 | document.addEventListener("keyup", function (e) { 115 | if (e.keyCode === 82) { 116 | console.log("Up"); 117 | updateImage(); 118 | } 119 | }); 120 | }; 121 | 122 | 123 | window.onload = function () { 124 | "use strict"; 125 | initInputs(); 126 | initParameters(); 127 | for (var p in parameters) { 128 | 129 | } 130 | var callbackInit = function (evt) { 131 | }; 132 | var callback = function (evt, type) { 133 | }; 134 | SC = new SuperCanvas(document.body); 135 | }; 136 | -------------------------------------------------------------------------------- /examples/gameoflife/gameoflife.js: -------------------------------------------------------------------------------- 1 | /*global window, console, document, Matrix, Colorspaces, CIE, open */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | var IMAGE, TIMER, sCanvas; 5 | 6 | function updateOutput(image, init) { 7 | 'use strict'; 8 | sCanvas.displayImage(image, 0, init); 9 | } 10 | 11 | window.GAME_OF_LIFE = 1; 12 | window.GAME_OF_LIFE_ID = 0; 13 | window.GAME_OF_LIFE_SPEED = 0; 14 | 15 | function createGameOfLife(image) { 16 | 'use strict'; 17 | // Game controls 18 | var A = image.getCopy(); 19 | // Parameters 20 | var xsize = image.getSize(1), ysize = image.getSize(0); 21 | 22 | // Patterns 23 | var cross = Matrix.fromArray([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 24 | [0, 0, 0, 1, 1, 1, 1, 0, 0, 0], 25 | [0, 0, 0, 1, 0, 0, 1, 0, 0, 0], 26 | [0, 1, 1, 1, 0, 0, 1, 1, 1, 0], 27 | [0, 1, 0, 0, 0, 0, 0, 0, 1, 0], 28 | [0, 1, 0, 0, 0, 0, 0, 0, 1, 0], 29 | [0, 1, 1, 1, 0, 0, 1, 1, 1, 0], 30 | [0, 0, 0, 1, 0, 0, 1, 0, 0, 0], 31 | [0, 0, 0, 1, 1, 1, 1, 0, 0, 0], 32 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]); 33 | 34 | //var A = Matrix.zeros(ysize, xsize); 35 | //A.set([ysize / 2, ysize / 2 + cross.size(0) - 1], 36 | // [xsize / 2, xsize / 2 + cross.size(1) - 1], 37 | // cross); 38 | 39 | /* 40 | var A = Matrix.zeros(ysize, xsize); 41 | A.set([ysize / 2, ysize / 2 + 6], [xsize / 2, xsize / 2 + 6], replicator); 42 | */ 43 | var H = Matrix.fromArray([[1, 1, 1], [1, 0, 1], [1, 1, 1]]); 44 | 45 | var isFirst = true; 46 | function display() { 47 | sCanvas.displayImage(A, 0, isFirst); 48 | if (isFirst === true) { 49 | isFirst = false; 50 | } 51 | } 52 | 53 | function iteration() { 54 | if (window.GAME_OF_LIFE) { 55 | // B3S23 rule 56 | // Neighborhood for each cell 57 | var N = A.imfilter(H), N3 = N['==='](3), N2 = N['==='](2); 58 | // Update step 59 | A = N3['||'](A['&&'](N2)); 60 | 61 | // B36/S23 rule 62 | //var N = A.filter(H), N3 = N['==='](3), N2 = N['==='](2); 63 | //var N6 = N['==='](6); 64 | //var D = A['==='](0); 65 | // Update step 66 | //var B = D['&&'](N3['||'](N6)), S = A['&&'](N2['||'](N3)); 67 | //A = B['||'](S); 68 | 69 | display(); 70 | } 71 | window.TIMER = window.setTimeout(iteration, window.GAME_OF_LIFE_SPEED); 72 | } 73 | 74 | iteration(); 75 | } 76 | 77 | var random = function () { 78 | 'use strict'; 79 | window.GAME_OF_LIFE_SPEED = parseFloat($('speed').value); 80 | 81 | var ratio = sCanvas.canvas.width / sCanvas.canvas.height; 82 | var xsize = Math.floor($I("size")); 83 | var ysize = Math.floor($I("size") / ratio); 84 | var p = 1 - parseFloat($('proba').value); 85 | 86 | // Initialization 87 | var A = Matrix.rand(ysize, xsize)['>'](p); 88 | if (window.TIMER !== undefined) { 89 | window.clearTimeout(window.TIMER); 90 | } 91 | createGameOfLife(A); 92 | }; 93 | 94 | window.onload = function () { 95 | 'use strict'; 96 | 97 | $('random').addEventListener('click', random); 98 | $('speed').addEventListener('change', function () { 99 | window.GAME_OF_LIFE_SPEED = parseFloat($('speed').value); 100 | }); 101 | var callback = function (evt) { 102 | var onread = function () { 103 | if (window.TIMER !== undefined) { 104 | window.clearTimeout(window.TIMER); 105 | } 106 | var proba = Math.round((1 - $('proba').value) * 255); 107 | IMAGE = this.rgb2gray()[">"](proba); 108 | updateOutput(IMAGE, true); 109 | createGameOfLife(IMAGE); 110 | }; 111 | var im = new Image(); 112 | im.src = this; 113 | im.onload = function() { 114 | im.height = 50; 115 | im.style.marginRight = "3px"; 116 | $("images").appendChild(im); 117 | } 118 | im.onclick = function () { 119 | Matrix.imread(im.src, onread); 120 | } 121 | }; 122 | 123 | sCanvas = new SuperCanvas(document.body); 124 | initFileUpload("loadFile", callback); 125 | initInputs(); 126 | var fieldsets = initFieldset(); 127 | fieldsets.hideAll(); 128 | document.body.onresize = updateOutput; 129 | }; 130 | -------------------------------------------------------------------------------- /examples/sift/sift.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Color descriptors matching 28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 42 | 43 | 50 | 51 | 57 | 58 |
59 | 60 | 68 | 69 | 70 | 74 | 75 | 76 | 77 | 78 |
79 | 80 | 89 | 90 | 96 | 97 | 101 | 102 |
103 |
104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /doc/guides/functions/README.md: -------------------------------------------------------------------------------- 1 | ## Matrix construction 2 | 3 | + {@link Matrix#colon} 4 | + {@link Matrix#linspace} 5 | + {@link Matrix#zeros} 6 | + {@link Matrix#ones} 7 | + {@link Matrix#rand} 8 | + {@link Matrix#randn} 9 | + {@link Matrix#randi} 10 | + {@link Matrix#eye} 11 | + {@link Matrix#complex} 12 | + {@link Matrix#imread} 13 | + {@link Matrix#diag} 14 | 15 | ## Matrix information 16 | 17 | + {@link Matrix#numel} 18 | + {@link Matrix#ndims} 19 | + {@link Matrix#size} 20 | + {@link Matrix#type} 21 | + {@link Matrix#isrow} 22 | + {@link Matrix#iscolumn} 23 | + {@link Matrix#isvector} 24 | + {@link Matrix#ismatrix} 25 | + {@link Matrix#issquare} 26 | + {@link Matrix#isinteger} 27 | + {@link Matrix#isfloat} 28 | + {@link Matrix#islogical} 29 | + {@link Matrix#intmin} 30 | + {@link Matrix#intmax} 31 | + {@link Matrix#realmin} 32 | + {@link Matrix#realmax} 33 | 34 | ## Matrix manipulation 35 | 36 | + {@link Matrix#set} 37 | + {@link Matrix#get} 38 | + {@link Matrix#repmat} 39 | + {@link Matrix#permute} 40 | + {@link Matrix#ipermute} 41 | + {@link Matrix#shiftdim} 42 | + {@link Matrix#rot90} 43 | + {@link Matrix#flipdim} 44 | + {@link Matrix#fliplr} 45 | + {@link Matrix#flipud} 46 | + {@link Matrix#cat} 47 | 48 | ## Linear algebra 49 | 50 | + {@link Matrix#mtimes} 51 | + {@link Matrix#chol} 52 | + {@link Matrix#inv} 53 | + {@link Matrix#det} 54 | + {@link Matrix#rank} 55 | + {@link Matrix#lu} 56 | + {@link Matrix#lup} 57 | + {@link Matrix#qr} 58 | + {@link Matrix#qrp} 59 | + {@link Matrix#mldivide} 60 | + {@link Matrix#mrdivide} 61 | + {@link Matrix#bidiag} 62 | + {@link Matrix#svd} 63 | 64 | ## Operators 65 | 66 | ### Mathematic operators 67 | 68 | + {@link Matrix#sqrt} 69 | + {@link Matrix#cos} 70 | + {@link Matrix#sin} 71 | + {@link Matrix#tan} 72 | + {@link Matrix#exp} 73 | + {@link Matrix#log} 74 | + {@link Matrix#floor} 75 | + {@link Matrix#ceil} 76 | + {@link Matrix#round} 77 | + {@link Matrix#acos} 78 | + {@link Matrix#asin} 79 | + {@link Matrix#atan} 80 | + {@link Matrix#atan2} 81 | 82 | ### Arimthmetic operators 83 | 84 | + {@link Matrix#plus} 85 | + {@link Matrix#minus} 86 | + {@link Matrix#uminus} 87 | + {@link Matrix#times} 88 | + {@link Matrix#rdivide} 89 | + {@link Matrix#ldivide} 90 | + {@link Matrix#power} 91 | 92 | ### Boolean operators 93 | 94 | + {@link Matrix#eq} 95 | + {@link Matrix#ne} 96 | + {@link Matrix#gt} 97 | + {@link Matrix#ge} 98 | + {@link Matrix#lt} 99 | + {@link Matrix#le} 100 | + {@link Matrix#and} 101 | + {@link Matrix#or} 102 | + {@link Matrix#neg} 103 | 104 | ### Other operators 105 | 106 | + {@link Matrix#arrayfun} 107 | + {@link Matrix#transpose} 108 | + {@link Matrix#ctranspose} 109 | + {@link Matrix#norm} 110 | + {@link Matrix#triu} 111 | + {@link Matrix#tril} 112 | + {@link Matrix#diag} 113 | 114 | ## Numerical types 115 | 116 | + {@link Matrix#cast} 117 | + {@link Matrix#double} 118 | + {@link Matrix#single} 119 | + {@link Matrix#int8} 120 | + {@link Matrix#int16} 121 | + {@link Matrix#int32} 122 | + {@link Matrix#uint8} 123 | + {@link Matrix#uint8c} 124 | + {@link Matrix#uint16} 125 | + {@link Matrix#uint32} 126 | + {@link Matrix#isnan} 127 | + {@link Matrix#isinf} 128 | + {@link Matrix#isfinite} 129 | 130 | ## Image processing 131 | 132 | ### Image conversion 133 | 134 | + {@link Matrix#convertImage} 135 | + {@link Matrix#im2double} 136 | + {@link Matrix#im2single} 137 | + {@link Matrix#im2uint8} 138 | + {@link Matrix#im2uint8c} 139 | + {@link Matrix#getImageData} 140 | + {@link Matrix#toImage} 141 | 142 | ### Image filtering 143 | 144 | + {@link Matrix#fspecial} 145 | + {@link Matrix#imfilter} 146 | + {@link Matrix#separableFilter} 147 | + {@link Matrix#gaussian} 148 | + {@link Matrix#gaussianGradient} 149 | + {@link Matrix#fastBlur} 150 | + {@link Matrix#gradient} 151 | + {@link Matrix#imerode} 152 | + {@link Matrix#imdilate} 153 | + {@link Matrix#imopen} 154 | + {@link Matrix#imclose} 155 | + {@link Matrix#fft2} 156 | + {@link Matrix#ifft2} 157 | 158 | ### Color image processing 159 | 160 | + {@link Matrix#applycform} 161 | + {@link Matrix#toColormap} 162 | 163 | ### Miscellaneous functions 164 | 165 | + {@link Matrix#imshow} 166 | + {@link Matrix#print} 167 | + {@link Matrix#imagesc} 168 | + {@link Matrix#imtransform} 169 | + {@link Matrix#imhist} 170 | + {@link Matrix#histeq} 171 | + {@link Matrix#rgb2gray} 172 | 173 | ## Basic mathematics 174 | 175 | ### Complex numbers 176 | 177 | + {@link Matrix#real} 178 | + {@link Matrix#imag} 179 | + {@link Matrix#complex} 180 | + {@link Matrix#angle} 181 | + {@link Matrix#abs} 182 | + {@link Matrix#conj} 183 | + {@link Matrix#ctranspose} 184 | 185 | ### Special functions 186 | 187 | + {@link Matrix#erf} 188 | + {@link Matrix#erfc} 189 | + {@link Matrix#erfcx} 190 | 191 | 192 | ## Basic statistics 193 | 194 | + {@link Matrix#min} 195 | + {@link Matrix#amin} 196 | + {@link Matrix#max} 197 | + {@link Matrix#amax} 198 | + {@link Matrix#sum} 199 | + {@link Matrix#prod} 200 | + {@link Matrix#mean} 201 | + {@link Matrix#variance} 202 | + {@link Matrix#std} 203 | + {@link Matrix#cumsum} 204 | + {@link Matrix#cumprod} 205 | + {@link Matrix#poissrnd} 206 | + {@link Matrix#exprnd} 207 | + {@link Matrix#sort} 208 | + {@link Matrix#asort} 209 | + {@link Matrix#accumarray} 210 | 211 | -------------------------------------------------------------------------------- /examples/console/ScriptArea.class.js: -------------------------------------------------------------------------------- 1 | /*global jsConsole, myScript, Disk, prompt, confirm*/ 2 | 3 | function ScriptArea(area, defaultScript) { 4 | 'use strict'; 5 | this.area = area; 6 | this.buffers = {}; 7 | this.initBuffers(); 8 | } 9 | 10 | ScriptArea.prototype.initBuffers = function () { 11 | 'use strict'; 12 | this.jsFiles = Disk.getItemList('.js'); 13 | var i, name; 14 | for (i = 0; i < this.jsFiles.length; i++) { 15 | this.load(this.jsFiles[i]); 16 | } 17 | if (this.jsFiles[0]) { 18 | this.selectBuffer(this.jsFiles[0]); 19 | } else { 20 | this.createBuffer(); 21 | } 22 | }; 23 | 24 | ScriptArea.prototype.createBuffer = function () { 25 | 'use strict'; 26 | var name = prompt('Please enter file name', 'myFile.js'); 27 | var msg = "File: '" + name + "' exist. Overwrite ?"; 28 | if ((this.buffers[name] === undefined && !Disk.exist(name)) || confirm(msg)) { 29 | this.buffers[name] = ''; 30 | this.selectBuffer(name); 31 | } 32 | }; 33 | 34 | ScriptArea.prototype.selectBuffer = function (name) { 35 | 'use strict'; 36 | var buffer = this.buffers[name]; 37 | this.setValue(buffer); 38 | this.currentBuffer = name; 39 | }; 40 | 41 | ScriptArea.prototype.changeBuffer = function (name) { 42 | 'use strict'; 43 | // Save current buffer 44 | this.buffers[this.currentBuffer] = this.getValue(); 45 | this.selectBuffer(name); 46 | }; 47 | 48 | ScriptArea.prototype.load = function (name) { 49 | 'use strict'; 50 | var file = Disk.load(name); 51 | this.buffers[name] = file; 52 | }; 53 | 54 | // Sauvegarde la zone 55 | ScriptArea.prototype.save = function (name) { 56 | 'use strict'; 57 | var file; 58 | if (name === undefined) { 59 | name = this.currentBuffer; 60 | file = this.getValue(); 61 | } else { 62 | file = this.buffers[name]; 63 | } 64 | Disk.save(name, file, true); 65 | }; 66 | 67 | ScriptArea.prototype.saveAs = function () { 68 | 'use strict'; 69 | var name = prompt('Please enter file name', 'myFile.js'); 70 | var msg = "File: '" + name + "' exist. Overwrite ?"; 71 | if (!Disk.exist(name) || confirm(msg)) { 72 | this.buffers[name] = this.getValue(); 73 | this.save(name); 74 | this.selectBuffer(name); 75 | } 76 | }; 77 | 78 | ScriptArea.prototype.remove = function (name) { 79 | 'use strict'; 80 | if (name === undefined) { 81 | name = this.currentBuffer; 82 | } 83 | var msg = "File: Really remove '" + name + "'?"; 84 | if ((this.buffers[name] !== undefined || Disk.exist(name)) && confirm(msg)) { 85 | delete this.buffers[name]; 86 | Disk.remove(name); 87 | 88 | var i; 89 | for (i = 0; i < this.jsFiles.length; i++) { 90 | if (this.jsFiles[i] === name) { 91 | this.jsFiles.slice(i, 1); 92 | } 93 | } 94 | if (this.jsFiles[0] !== undefined) { 95 | this.selectBuffer(this.jsFiles[0]); 96 | } else { 97 | this.createBuffer(); 98 | } 99 | } 100 | }; 101 | 102 | // Efface la zone ainsi que la sauvegarde 103 | ScriptArea.prototype.clear = function () { 104 | 'use strict'; 105 | if (Disk.exist('__CURRENT__')) { 106 | Disk.remove('__CURRENT__'); 107 | } 108 | }; 109 | 110 | // Valeur de la zone 111 | ScriptArea.prototype.getValue = function () { 112 | 'use strict'; 113 | return this.area.getValue(); 114 | }; 115 | 116 | ScriptArea.prototype.setValue = function (value) { 117 | 'use strict'; 118 | if (value !== undefined) { 119 | this.area.setValue(value); 120 | } 121 | return this; 122 | }; 123 | 124 | ScriptArea.prototype.getSelection = function () { 125 | 'use strict'; 126 | var area = this.area; 127 | var selection = area.getSession().doc.getTextRange(area.getSelectionRange()); 128 | return selection; 129 | }; 130 | 131 | ScriptArea.prototype.gotoNextCodeLine = function () { 132 | 'use strict'; 133 | var lineNumber = this.area.getSession().getSelection().getCursor().row; 134 | var buffer = this.getValue(); 135 | var lines = buffer.split("\n"); 136 | 137 | if (lineNumber < lines.length - 1) { 138 | lineNumber++; 139 | } else { 140 | return; 141 | } 142 | 143 | while (lineNumber < lines.length - 1 && !this.isCodeLine(lines[lineNumber])) { 144 | lineNumber++; 145 | } 146 | 147 | if (this.isCodeLine(lines[lineNumber])) { 148 | this.area.gotoLine(lineNumber + 1); 149 | } 150 | }; 151 | 152 | ScriptArea.prototype.getCurrentLine = function () { 153 | 'use strict'; 154 | var lineNumber = this.area.getSession().getSelection().getCursor().row; 155 | var buffer = this.getValue().split('\n'); 156 | return buffer[lineNumber]; 157 | }; 158 | 159 | ScriptArea.prototype.isCodeLine = function (line) { 160 | 'use strict'; 161 | var reg = /(^[ ]*[\/]+)|(^[ };]*$)/g; 162 | return (line.match(reg)) ? false : true; 163 | }; 164 | -------------------------------------------------------------------------------- /src/Matrix/Matrix.elementary_math.complex_numbers.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /** @class Matrix */ 20 | 21 | (function (Matrix, Matrix_prototype) { 22 | "use strict"; 23 | 24 | /** Returns the Matrix real part. 25 | * 26 | * __Also see:__ 27 | * {@link Matrix#imag}. 28 | * 29 | * @return {Matrix} 30 | * 31 | * @matlike 32 | */ 33 | Matrix_prototype.real = function () { 34 | if (this.isreal()) { 35 | throw new Error('Matrix.real: This function can be only' + 36 | ' used with a complex Matrix. '); 37 | } 38 | var rd = this.getRealData(); 39 | return new Matrix(this.getSize(), new rd.constructor(rd)); 40 | }; 41 | 42 | /** Returns the Matrix imaginary part. 43 | * 44 | * __Also see:__ 45 | * {@link Matrix#real}. 46 | * 47 | * @return {Matrix} 48 | * 49 | * @matlike 50 | */ 51 | Matrix_prototype.imag = function () { 52 | if (this.isreal()) { 53 | throw new Error('Matrix.imag: This function can be only' + 54 | ' used with a complex Matrix. '); 55 | } 56 | var id = this.getImagData(); 57 | return new Matrix(this.getSize(), new id.constructor(id)); 58 | }; 59 | 60 | /** Returns the phase angle for complex Matrix. 61 | * 62 | * When used as Matrix object method, this function acts in place. 63 | * Use the Matrix.angle property to work on a copy. 64 | * 65 | * __Also see:__ 66 | * {@link Matrix#abs}. 67 | * 68 | * @chainable 69 | * @matlike 70 | * @method angle 71 | */ 72 | (function () { 73 | var angle_real = function (data) { 74 | for (var i = 0, ie = data.length; i < ie; i++) { 75 | data[i] = 0; 76 | } 77 | }; 78 | 79 | var angle_cplx = function (datar, datai) { 80 | for (var i = 0, ie = datar.length; i < ie; i++) { 81 | datar[i] = Math.atan2(datai[i], datar[i]); 82 | datai[i] = 0; 83 | } 84 | }; 85 | 86 | Matrix_prototype.angle = function () { 87 | if (this.isreal()) { 88 | angle_real(this.getData()); 89 | } else { 90 | angle_cplx(this.getRealData(), this.getImagData()); 91 | } 92 | return this; 93 | }; 94 | Matrix.angle = function (m) { 95 | return m.getCopy().angle(); 96 | }; 97 | 98 | })(); 99 | 100 | /** Returns the absolute value for real Matrix and 101 | * the complex magnitude for complex Matrix. 102 | * 103 | * When used as Matrix object method, this function acts in place. 104 | * Use the Matrix.abs property to work on a copy. 105 | * 106 | * __Also see:__ 107 | * {@link Matrix#angle}. 108 | * 109 | * @chainable 110 | * @matlike 111 | * @method abs 112 | */ 113 | (function () { 114 | var abs_real = function (data) { 115 | for (var i = 0, ie = data.length; i < ie; i++) { 116 | data[i] = data[i] > 0 ? data[i] : -data[i]; 117 | } 118 | }; 119 | 120 | var abs_cplx = function (datar, datai) { 121 | for (var i = 0, ie = datar.length; i < ie; i++) { 122 | var a = datai[i], b = datar[i]; 123 | datar[i] = Math.sqrt(a * a + b * b); 124 | datai[i] = 0; 125 | } 126 | }; 127 | 128 | Matrix_prototype.abs = function () { 129 | if (this.isreal()) { 130 | abs_real(this.getData()); 131 | } else { 132 | abs_cplx(this.getRealData(), this.getImagData()); 133 | } 134 | return this; 135 | }; 136 | Matrix.abs = function (m) { 137 | return m.getCopy().abs(); 138 | }; 139 | })(); 140 | 141 | /** Returns the complex conjugate of each element of the Matrix. 142 | * 143 | * When used as Matrix object method, this function acts in place. 144 | * Use the Matrix.conj property to work on a copy. 145 | * 146 | * @matlike 147 | * @chainable 148 | */ 149 | Matrix_prototype.conj = function () { 150 | if (this.isreal() === true) { 151 | return this; 152 | } 153 | var i, ie, imag = this.getImagData(); 154 | for (i = 0, ie = imag.length; i < ie; i++) { 155 | imag[i] = -imag[i]; 156 | } 157 | return this; 158 | }; 159 | Matrix.conj = function (m) { 160 | return m.getCopy().conj(); 161 | }; 162 | 163 | })(Matrix, Matrix.prototype); 164 | -------------------------------------------------------------------------------- /examples/gpu/benchmark.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, nomen: true, browser: true, plusplus: true, devel: true */ 2 | /*global GLEffect, GLImage, GLReduction, FileReader, Uint8Array, Float32Array, Float64Array */ 3 | /*exported init */ 4 | 5 | 'use strict'; 6 | 7 | 8 | // Global variables 9 | var REDUCTION, GRAYIFYER, MIXER; 10 | var IMAGE, TIME; 11 | 12 | // Shortcut for 'getElementById' 13 | function $(str) { 14 | return window.document.getElementById(str); 15 | } 16 | 17 | // Remove all the children of a node 18 | function removeAllChildren(elmt) { 19 | while (elmt.lastChild) { 20 | elmt.removeChild(elmt.lastChild); 21 | } 22 | } 23 | 24 | // Sum all the values of an array 25 | function sumAll(array) { 26 | var sum, k, n = array.length; 27 | for (sum = 0, k = 0; k < n; ++k) { 28 | sum += array[k]; 29 | } 30 | return sum; 31 | } 32 | 33 | // Convert an array to a float array 34 | function toFloatArray(array, OutType) { 35 | OutType = OutType || Float32Array; 36 | var out = new OutType(array); 37 | var k, n = out.length; 38 | for (k = 0; k < n; ++k) { 39 | out[k] /= 255; 40 | } 41 | return out; 42 | } 43 | 44 | // Sum of an image's values 45 | function imageSum(im) { 46 | var c = document.createElement('canvas'); 47 | c.width = im.width; 48 | c.height = im.height; 49 | var ctx = c.getContext('2d'); 50 | ctx.drawImage(im, 0, 0, im.width, im.height); 51 | return sumAll(ctx.getImageData(0, 0, im.width, im.height).data); 52 | } 53 | 54 | // The time, in ms 55 | function tic() { 56 | var former = TIME; 57 | TIME = new Date().getTime(); 58 | return TIME - former; 59 | } 60 | 61 | // Relative error 62 | function display(str, ref, value) { 63 | console.log('[' + tic() + 'ms] ' + str); 64 | if (ref) { 65 | console.log(Math.abs(value / ref - 1)); 66 | } 67 | } 68 | 69 | // Create and run the GLEffect 70 | function runEffect() { 71 | var sum = imageSum(IMAGE); 72 | var im = new GLImage(); 73 | im.load(IMAGE); 74 | tic(); 75 | 76 | // Check time 77 | console.log('--- Number of CPU operations ---'); 78 | var iterCPU; 79 | for (iterCPU = 1; iterCPU <= im.width * im.height; iterCPU *= 2) { 80 | display(iterCPU, null, 81 | 255 * sumAll(REDUCTION.run(im, {'maxIterCPU': iterCPU}))); 82 | } 83 | 84 | // Check precision 85 | console.log('--- Precision ---'); 86 | display('Manual, Float32', sum, 87 | 255 * sumAll(toFloatArray(im.toArray(Uint8Array), Float32Array))); 88 | display('Manual, Float64', sum, 89 | 255 * sumAll(toFloatArray(im.toArray(Uint8Array), Float64Array))); 90 | display('GLImage, Uint8', sum, 91 | sumAll(im.toArray(Uint8Array))); 92 | display('GLImage, Float32', sum, 93 | 255 * sumAll(im.toArray(Float32Array))); 94 | display('Reducer, GPU', sum, 95 | 255 * sumAll(REDUCTION.run(im, {'maxIterCPU': 0}))); 96 | display('Reducer, CPU', sum, 97 | 255 * sumAll(REDUCTION.run(im, {'maxIterCPU': Infinity}))); 98 | display('Reducer, hybrid', sum, 99 | 255 * sumAll(REDUCTION.run(im))); 100 | 101 | // Display 102 | var gray = GRAYIFYER.run(im, new GLImage()); 103 | var canvas = MIXER.run([im, gray]); 104 | var container = $('content'); 105 | removeAllChildren(container); 106 | container.appendChild(canvas); 107 | 108 | var slider = $('slider'); 109 | slider.style.display = ''; 110 | slider.value = 0; 111 | slider.oninput = function () { 112 | MIXER.setParameter('alpha', slider.value); 113 | MIXER.run([im, gray]); 114 | slider.focus(); 115 | }; 116 | } 117 | 118 | // Callback function: load the image 119 | function loadImageFromUrl() { 120 | var im = new Image(); 121 | im.onload = function () { 122 | IMAGE = im; 123 | runEffect(); 124 | }; 125 | im.src = this; 126 | } 127 | 128 | // Callback function: handle the selected file 129 | function fileSelectionCallback() { 130 | if (this.files.length) { 131 | var file = this.files[0]; 132 | var type = file.type.match(new RegExp('^[^/]*'))[0]; 133 | if (type !== 'image') { 134 | throw new Error('Invalid image type'); 135 | } 136 | var reader = new FileReader(); 137 | reader.onerror = function () { 138 | throw new Error('Cannot load the selected file'); 139 | }; 140 | reader.onload = function () { 141 | loadImageFromUrl.call(reader.result); 142 | }; 143 | reader.readAsDataURL(file); 144 | } 145 | } 146 | 147 | // Allow this element to be dropped on 148 | function makeDropArea(elmt) { 149 | elmt.ondrop = function (evt) { 150 | evt.preventDefault(); 151 | fileSelectionCallback.call(evt.dataTransfer); 152 | }; 153 | elmt.ondragover = function (evt) { 154 | evt.preventDefault(); 155 | evt.stopPropagation(); 156 | }; 157 | } 158 | 159 | // Initialize the demo 160 | function init() { 161 | makeDropArea(document); 162 | REDUCTION = GLReduction.fromFunctions( 163 | function (a, b) { 164 | return a + b; 165 | }, 166 | [ 167 | 'vec4 function(vec4 a, vec4 b) {', 168 | ' return a + b;', 169 | '}' 170 | ].join('\n') 171 | ); 172 | GRAYIFYER = GLEffect.fromFunction([ 173 | 'vec3 function(vec3 color) {', 174 | ' vec3 axis = vec3(0.2, 0.5, 0.3);', 175 | ' float gray = dot(color, axis);', 176 | ' return vec3(gray);', 177 | '}' 178 | ].join('\n')); 179 | MIXER = GLEffect.fromFunction([ 180 | 'uniform float alpha;', 181 | 'vec3 function(vec3 a, vec3 b) {', 182 | ' return alpha * b + (1.0 - alpha) * a;', 183 | '}' 184 | ].join('\n')); 185 | } -------------------------------------------------------------------------------- /projects/drawHistogram.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /*global document, Float32Array, Float64Array, console, Matrix, Colorspaces*/ 20 | /*jshint white:true */ 21 | 22 | (function() { 23 | 24 | // Check if code is running inside a browser or not. 25 | if (typeof window === 'undefined') { 26 | return; 27 | } 28 | 29 | HTMLCanvasElement.prototype.drawHistogram = function (data, vMax, title, modes, colormap, erase) { 30 | "use strict"; 31 | 32 | var ctx = this.getContext('2d'), xSize = this.width, ySize = this.height; 33 | var max = 0; 34 | var xHisto = xSize - 80, yHisto = ySize - 45, binWidth = 0; 35 | 36 | var setTitle = function (title) { 37 | ctx.font = Math.round(Math.min(xSize, ySize) / 15) + "pt sans-serif"; 38 | ctx.textAlign = "center"; 39 | ctx.textBaseline = 'middle'; 40 | 41 | if (title === undefined) { 42 | title = "Histogram"; 43 | } 44 | ctx.fillText(title, xSize / 2, 15); 45 | }; 46 | var initalize = function (erase) { 47 | if (erase) { 48 | ctx.clearRect(0, 0, xSize, ySize); 49 | } 50 | // Draw border 51 | ctx.lineWidth = 0.5; 52 | ctx.beginPath(); 53 | ctx.strokeStyle = "black"; 54 | ctx.strokeRect(0, 0, xSize, ySize); 55 | 56 | 57 | // Save properties 58 | ctx.save(); 59 | 60 | // Translation 61 | ctx.translate((xSize - xHisto) / 2, ySize - 20); 62 | 63 | // Dessin des axes de l'histogramme 64 | ctx.strokeStyle = "black"; 65 | ctx.lineWidth = 0.5; 66 | 67 | ctx.beginPath(); 68 | ctx.moveTo(-10, 0); 69 | ctx.lineTo(xHisto, 0); 70 | ctx.moveTo(0, 0); 71 | ctx.lineTo(0, -yHisto); 72 | 73 | ctx.moveTo(0, -0.9 * yHisto); 74 | ctx.lineTo(-5, -0.9 * yHisto); 75 | ctx.stroke(); 76 | 77 | }; 78 | var setMax = function () { 79 | ctx.font = "8pt Arial"; 80 | ctx.strokeStyle = "black"; 81 | ctx.fillStyle = "black"; 82 | 83 | var i; 84 | for (i = 0; i < data.length; i++) { 85 | if (data[i] > max) { 86 | max = data[i]; 87 | } 88 | } 89 | if (max > vMax) { 90 | vMax = max; 91 | } 92 | if (vMax > 0) { 93 | vMax = 1 / vMax; 94 | } 95 | ctx.beginPath(); 96 | //ctx.fillText(Math.round(100 / vMax) / 100, -21, -0.9 * yHisto); 97 | 98 | ctx.stroke(); 99 | }; 100 | var drawBins = function () { 101 | var round = Math.round; 102 | for (var i = 0; i < data.length; i++) { 103 | var h = -data[i] * vMax * 0.9 * yHisto; 104 | // Bins color 105 | ctx.fillStyle = colormap === "hue" ? 106 | "hsl(" + round(i / data.length * 360) + ", 100%, 50%" : (colormap ? colormap : "rgb(0, 128, 255)"); 107 | // Draw line 108 | ctx.fillRect(i * binWidth + 4, 0, binWidth - 4, h); 109 | } 110 | }; 111 | 112 | var drawModes = function (modes) { 113 | // Border color 114 | ctx.lineWidth = 2; 115 | ctx.strokeStyle = "rgb(255, 0, 128)"; 116 | ctx.beginPath(); 117 | for (var m = 0; m < modes.length; m++) { 118 | if (modes[m].bins[1] >= modes[m].bins[0]) { 119 | ctx.moveTo(modes[m].bins[0] * binWidth + 2, 0); 120 | ctx.lineTo(modes[m].bins[0] * binWidth + 2, -0.9 * yHisto); 121 | ctx.lineTo((modes[m].bins[1] + 1) * binWidth + 2, -0.9 * yHisto); 122 | ctx.lineTo((modes[m].bins[1] + 1) * binWidth + 2, 0); 123 | 124 | } else { 125 | ctx.moveTo(modes[m].bins[0] * binWidth + 2, 0); 126 | ctx.lineTo(modes[m].bins[0] * binWidth + 2, -0.9 * yHisto); 127 | ctx.lineTo(data.length * binWidth + 2, -0.9 * yHisto); 128 | ctx.moveTo(0, -0.9 * yHisto); 129 | ctx.lineTo((modes[m].bins[1] + 1) * binWidth + 2, -0.9 * yHisto); 130 | ctx.lineTo((modes[m].bins[1] + 1) * binWidth + 2, 0); 131 | } 132 | } 133 | ctx.stroke(); 134 | }; 135 | 136 | setTitle(title); 137 | initalize(erase === false ? false : true); 138 | if (!data) { 139 | ctx.restore(); 140 | return; 141 | } 142 | binWidth = (xHisto - 20) / data.length; 143 | 144 | setMax(); 145 | drawBins(); 146 | if (modes) { 147 | drawModes(modes); 148 | } 149 | // Restore properties 150 | ctx.restore(); 151 | }; 152 | 153 | })(); 154 | -------------------------------------------------------------------------------- /examples/gpu/effect-designer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GPU Processing UI 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 |
Images
31 | 32 | 33 |
34 |

35 | Load an image/video and import an effect to start the demo. 36 | 37 |

38 |

What is this?

39 |

40 | This page allows you to write and run real-time effects on images and videos. 41 | It is a graphical interface for the GLEffect and GLReduction classes. 42 |

43 |

Known bugs:

44 |
    45 |
  • Firefox throws an error when double-clicking the output, but the format/type pair is correct.
  • 46 |
  • When loading mobile version then turning to desktop one, bug when resizing the menu.
  • 47 |
48 |

To do:

49 |
    50 |
  • Nothing!
  • 51 |
52 |
53 | 54 | 55 | 114 | 115 | 116 |
117 | 119 | 122 | 125 | 128 |
131 | 133 |
136 | 137 |
138 | 139 | 140 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /examples/colorenhancement/demo.js: -------------------------------------------------------------------------------- 1 | /*global console, document, Matrix, Colorspaces, CIE, open */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | var IMAGE_ORIG, IMAGE_PROCESSED, DIFF, MAX_SIZE = 1200; 5 | var sCanvas; 6 | var STRETCH = false; 7 | 8 | var stretchLuminance = function (im) { 9 | "use strict" 10 | var l = im.mean(2), lm = l.min(), lM = l.max(); 11 | var ls = l["-"](lm)["./"](lM["-"](lm)); 12 | var ld = l.getData(), lsd = ls.getData(), od = im.getData(); 13 | var e = ld.length; 14 | for (var r = 0, g = e, b = 2 * e; r < e; r++, g++, b++) { 15 | var cst = ld[r] <= 0 ? 0 : lsd[r] / ld[r]; 16 | cst = cst > 1 ? 1 : cst; 17 | od[r] *= cst; 18 | od[g] *= cst; 19 | od[b] *= cst; 20 | } 21 | }; 22 | 23 | var stretchColorChannels = function (im) { 24 | "use strict"; 25 | for (var c = 0; c < 3; c++) { 26 | var channel = im.get([], [], c); 27 | var min = channel.min(), max = channel.max(); 28 | channel["-="](min)["/="](max["-"](min)); 29 | im.set([], [], c, channel); 30 | } 31 | }; 32 | 33 | function updateOutput(init) { 34 | "use strict"; 35 | if (!IMAGE_ORIG) { 36 | return; 37 | } 38 | var image; 39 | if ($V("view") === "proc") { 40 | image = IMAGE_PROCESSED; 41 | if ($V('stretchDyn') === "lum") { 42 | image = image.get(); 43 | stretchLuminance(image); 44 | } else if ($V('stretchDyn') === "color") { 45 | image = image.get(); 46 | stretchColorChannels(image); 47 | } 48 | } else if ($V("view") === "orig") { 49 | image = IMAGE_ORIG; 50 | } else if ($V("view") === "diff") { 51 | DIFF = IMAGE_PROCESSED["-"](IMAGE_ORIG).abs(); 52 | var min = DIFF.min(), max = DIFF.max(); 53 | image = DIFF["-="](min)["/="](max["-"](min)); 54 | } 55 | sCanvas.displayImage(image, 0, init); 56 | drawImageHistogram("histogram", image); 57 | } 58 | 59 | var colEn = function () { 60 | "use strict"; 61 | Matrix.dwtmode("sym"); 62 | var getParameters = function () { 63 | return { 64 | K: $F("K"), 65 | gamma: $F("gamma"), 66 | alpha: $F("alpha"), 67 | w: $F("w") / 255, 68 | wav: $V("wavelet"), 69 | colorspace: $V("colorspace"), 70 | averageValue: $V("averageValue") 71 | }; 72 | }; 73 | 74 | colEn.reset = function () { 75 | Tools.tic(); 76 | $F("K", 20); 77 | $F("gamma", 0.5); 78 | $F("alpha", 0.1); 79 | $F("w", 15.0); 80 | $("wavelet").getElementsByTagName("option")[0].selected = "selected"; 81 | $("wavelet").getElementsByTagName("option")[0].selected = "selected"; 82 | $F("Gamma", 1.0); 83 | $("stretchDyn").getElementsByTagName("option")[0].selected = "selected"; 84 | $("colorspace").getElementsByTagName("option")[0].selected = "selected"; 85 | onChange(); 86 | }; 87 | 88 | colEn.fun = function (img, p) { 89 | console.log(p.colorspace); 90 | if (p.colorspace === "Gray") { 91 | img = Matrix.applycform(img, "RGB to Ohta"); 92 | var L = img.get([], [], 0); 93 | L = L.colorEnhancementTest(p.gamma, p.w, p.K, p.wav, p.alpha, p.averageValue); 94 | return img.set([], [], 0, L).applycform("Ohta to RGB"); 95 | } 96 | if(p.colorspace !== "RGB") { 97 | img = Matrix.applycform(img, "RGB to " + p.colorspace); 98 | } 99 | img = img.colorEnhancementTest(p.gamma, p.w, p.K, p.wav, p.alpha, p.averageValue); 100 | if (p.colorspace !== "RGB") { 101 | img = img.applycform(p.colorspace + " to RGB"); 102 | } 103 | return img; 104 | }; 105 | 106 | var onApply = function () { 107 | Tools.tic(); 108 | var img = IMAGE_ORIG.get(); 109 | if (STRETCH) { 110 | stretchColorChannels(img); 111 | } 112 | img.power($F("Gamma")); 113 | IMAGE_PROCESSED = colEn.fun(img, getParameters()).power(1 / $F("Gamma")); 114 | console.log("Time elapsed:", Tools.toc(), "(ms)"); 115 | $("view").getElementsByTagName("option")[0].selected = "selected"; 116 | $("view").focus(); 117 | updateOutput(false); 118 | }; 119 | var onChange = function () { 120 | $V("KVal", $F("K")); 121 | $V("gammaVal", $F("gamma")); 122 | $V("GammaVal", $F("Gamma")); 123 | $V("alphaVal", $F("alpha")); 124 | $V("wVal", $F("w")); 125 | }; 126 | onChange(); 127 | $("K").addEventListener("change", onChange, false); 128 | $("w").addEventListener("change", onChange, false); 129 | $("alpha").addEventListener("change", onChange, false); 130 | $("gamma").addEventListener("change", onChange, false); 131 | $("Gamma").addEventListener("change", onChange, false); 132 | $("applyColEn").addEventListener("click", onApply, false); 133 | $("resetColEn").addEventListener("click", colEn.reset, false); 134 | }; 135 | 136 | 137 | 138 | window.onload = function () { 139 | "use strict"; 140 | var onread = function () { 141 | IMAGE_ORIG = limitImageSize(this.im2double(), MAX_SIZE); 142 | IMAGE_PROCESSED = IMAGE_ORIG; 143 | $("view").getElementsByTagName("option")[1].selected = "selected"; 144 | $("applyColEn").focus(); 145 | updateOutput(true); 146 | }; 147 | var addImage = function (src) { 148 | var im = new Image(); 149 | im.src = this; 150 | im.onload = function() { 151 | im.height = 50; 152 | im.style.marginRight = "3px"; 153 | $("images").appendChild(im); 154 | } 155 | im.onclick = function () { 156 | Matrix.imread(im.src, onread); 157 | } 158 | }; 159 | 160 | var pinImage = function () { 161 | IMAGE_PROCESSED.toImage(function () { 162 | addImage.bind(this.src)(); 163 | }); 164 | }; 165 | 166 | var paperResults = function () { 167 | if ($V("paperResults") === "YES") { 168 | window.EDO_RES = true; 169 | } else { 170 | window.EDO_RES = false; 171 | } 172 | }; 173 | 174 | initFileUpload("loadFile", addImage); 175 | initInputs(); 176 | var displayHelp = initHelp(); 177 | displayHelp(); 178 | colEn(); 179 | 180 | sCanvas = new SuperCanvas(document.body); 181 | 182 | $("view").addEventListener("change", updateOutput, false); 183 | $('stretchDyn').addEventListener("change", updateOutput, false); 184 | $('pinImage').addEventListener("click", pinImage, false); 185 | $('paperResults').addEventListener("change", paperResults, false); 186 | 187 | document.body.onresize = updateOutput; 188 | //hideFieldset(); 189 | }; 190 | 191 | -------------------------------------------------------------------------------- /examples/gpu/GLEffect.more.js: -------------------------------------------------------------------------------- 1 | /*global GLEffect, GLReduction */ 2 | 3 | 4 | /** Sample effects. @singleton @class GLEffect.Sample */ 5 | GLEffect.Sample = {}; 6 | 7 | /** Identity effect (using the raw source code). @return {GLEffect} */ 8 | GLEffect.Sample.identity_main = function () { 9 | 'use strict'; 10 | return new GLEffect(); 11 | }; 12 | 13 | /** Identity effect (using the RGB function form). @return {GLEffect} */ 14 | GLEffect.Sample.identity_RGB = function () { 15 | 'use strict'; 16 | return GLEffect.fromFunction( 17 | [ 18 | 'vec3 function(vec3 color) {', 19 | ' return color;', 20 | '}' 21 | ].join('\n') 22 | ); 23 | }; 24 | 25 | /** Identity effect (using the RGBA function form). @return {GLEffect} */ 26 | GLEffect.Sample.identity_RGBA = function () { 27 | 'use strict'; 28 | return GLEffect.fromFunction( 29 | [ 30 | 'vec4 function(vec4 color) {', 31 | ' return color;', 32 | '}' 33 | ].join('\n') 34 | ); 35 | }; 36 | 37 | /** Pixel-wise absolute value. @return {GLEffect} */ 38 | GLEffect.Sample.abs = function () { 39 | 'use strict'; 40 | return GLEffect.fromFunction( 41 | [ 42 | 'vec3 function(vec3 color) {', 43 | ' return abs(color);', 44 | '}' 45 | ].join('\n') 46 | ); 47 | }; 48 | 49 | /** Conversion to gray-level images. 50 | * @param {Float[4]} [weight] 51 | * Weights of the RGBA channels. 52 | * @return {GLEffect} */ 53 | GLEffect.Sample.gray = function (weights) { 54 | 'use strict'; 55 | return GLEffect.fromFunction( 56 | [ 57 | 'uniform vec4 weights;', 58 | 'vec4 function(vec4 color) {', 59 | ' float gray = dot(color, weights);', 60 | ' return vec4(vec3(gray), 1.0);', 61 | '}' 62 | ].join('\n'), 63 | { 64 | 'weights': weights || [0.3, 0.6, 0.1, 0.0] 65 | } 66 | ); 67 | }; 68 | 69 | /** Convolution by a 3x3 kernel. 70 | * @param {Float[9]} [kernel] 71 | * The convolution kernel. 72 | * @return {GLEffect} */ 73 | GLEffect.Sample.conv3x3 = function (kernel) { 74 | 'use strict'; 75 | return new GLEffect( 76 | GLEffect.sourceCodeHeader + [ 77 | 'uniform mat3 kernel; // convolution kernel', 78 | '', 79 | 'void main(void) {', 80 | ' vec2 x = vPosition;', 81 | ' vec2 dx = uPixel;', 82 | ' vec4 color = texture2D(uImage, x) * kernel[1][1]', 83 | ' + texture2D(uImage, x + dx * vec2( 0., -1.)) * kernel[1][0]', 84 | ' + texture2D(uImage, x + dx * vec2( 0., +1.)) * kernel[1][2]', 85 | ' + texture2D(uImage, x + dx * vec2(-1., 0.)) * kernel[0][1]', 86 | ' + texture2D(uImage, x + dx * vec2(+1., 0.)) * kernel[2][1]', 87 | ' + texture2D(uImage, x + dx * vec2(-1., -1.)) * kernel[0][0]', 88 | ' + texture2D(uImage, x + dx * vec2(-1., +1.)) * kernel[0][2]', 89 | ' + texture2D(uImage, x + dx * vec2(+1., -1.)) * kernel[2][0]', 90 | ' + texture2D(uImage, x + dx * vec2(+1., +1.)) * kernel[2][2];', 91 | ' gl_FragColor = vec4(color.rgb, 1.0);', 92 | '}' 93 | ].join('\n'), 94 | { 95 | 'kernel': kernel || [0, 0, 0, 0, 1, 0, 0, 0, 0] 96 | } 97 | ); 98 | }; 99 | 100 | /** Convolution by a 3x1 kernel. 101 | * @param {Float[2] || String} [direction = 'E'] 102 | * The axis of convolution.
103 | * Possible strings are: E, SE, S, SO, O, NO, N, NE. 104 | * @param {Float[3]} [kernel] 105 | * The convolution kernel. 106 | * @return {GLEffect} */ 107 | GLEffect.Sample.conv3x1 = function (kernel, direction) { 108 | 'use strict'; 109 | var dir = { 110 | E: [1, 0], 111 | SE: [1, 1], 112 | S: [0, 1], 113 | SO: [-1, 1], 114 | O: [-1, 0], 115 | NO: [-1, -1], 116 | N: [0, -1], 117 | NE: [1, -1] 118 | }; 119 | if (typeof direction === 'string') { 120 | direction = dir[direction.toUpperCase()]; 121 | if (!direction) { 122 | throw new Error('Invalid argument: unknown direction ' + direction); 123 | } 124 | } 125 | return new GLEffect( 126 | GLEffect.sourceCodeHeader + [ 127 | 'uniform vec2 direction; // axis of the convolution', 128 | 'uniform vec3 kernel; // convolution kernel', 129 | '', 130 | 'void main(void) {', 131 | ' vec2 dx = uPixel * direction;', 132 | ' vec4 color = texture2D(uImage, vPosition) * kernel[1]', 133 | ' + texture2D(uImage, vPosition - dx) * kernel[0]', 134 | ' + texture2D(uImage, vPosition + dx) * kernel[2];', 135 | ' gl_FragColor = vec4(color.rgb, 1.0);', 136 | '}' 137 | ].join('\n'), 138 | { 139 | 'direction': direction || [1, 0], 140 | 'kernel': kernel || [0, 1, 0] 141 | } 142 | ); 143 | }; 144 | 145 | // TODO: generic size convolution 146 | /* 147 | GLEffect.Sample.conv1d = new GLEffect( 148 | GLEffect.sourceCodeHeader + [ 149 | 'uniform float kernel[9]; // convolution kernel', 150 | 'uniform vec2 direction; // axis of the convolution', 151 | '', 152 | 'void main(void) {', 153 | ' vec2 dx = uPixel * direction;', 154 | ' vec4 color = texture2D(uImage, vPosition) * kernel[4]', 155 | ' + texture2D(uImage, vPosition - 4. * dx) * kernel[0]', 156 | ' + texture2D(uImage, vPosition - 3. * dx) * kernel[1]', 157 | ' + texture2D(uImage, vPosition - 2. * dx) * kernel[2]', 158 | ' + texture2D(uImage, vPosition - dx) * kernel[3]', 159 | ' + texture2D(uImage, vPosition + dx) * kernel[5]', 160 | ' + texture2D(uImage, vPosition + 2. * dx) * kernel[6]', 161 | ' + texture2D(uImage, vPosition + 3. * dx) * kernel[7]', 162 | ' + texture2D(uImage, vPosition + 4. * dx) * kernel[8];', 163 | ' gl_FragColor = vec4(color.rgb, 1.0);', 164 | '}' 165 | ].join('\n'), 166 | { 167 | 'kernel': [0, 0, 0, 0, 1, 0, 0, 0, 0], 168 | 'direction': [1, 0] 169 | } 170 | ); 171 | */ 172 | 173 | 174 | /** Sample reductions. @singleton @class GLReduction.Sample */ 175 | GLReduction.Sample = {}; 176 | 177 | /** Sum of all the RGBA values. @return {GLReduction} */ 178 | GLReduction.Sample.sum = function () { 179 | 'use strict'; 180 | return GLReduction.fromFunctions( 181 | function (a, b) { return a + b; }, 182 | 'vec4 function(vec4 a, vec4 b) { return a + b; }' 183 | ); 184 | }; 185 | 186 | /** Minimum R/G/B/A values. @return {GLReduction} */ 187 | GLReduction.Sample.min = function () { 188 | 'use strict'; 189 | return GLReduction.fromFunctions( 190 | Math.min, 191 | 'vec4 function(vec4 a, vec4 b) { return min(a, b); }' 192 | ); 193 | }; 194 | 195 | /** Maximum R/G/B/A values. @return {GLReduction} */ 196 | GLReduction.Sample.max = function () { 197 | 'use strict'; 198 | return GLReduction.fromFunctions( 199 | Math.max, 200 | 'vec4 function(vec4 a, vec4 b) { return max(a, b); }' 201 | ); 202 | }; 203 | -------------------------------------------------------------------------------- /examples/plot/plot-editor.js: -------------------------------------------------------------------------------- 1 | /*global console, Tools, document, FileReader, Plot*/ 2 | var filesData = []; 3 | 4 | var plot; 5 | var $ = function () { 6 | 'use strict'; 7 | return document.getElementById.apply(document, arguments); 8 | }; 9 | function updateOutput() { 10 | "use strict"; 11 | var div = $("image"); 12 | var canvasXSize = div.offsetWidth; 13 | var canvasYSize = div.offsetHeight; 14 | plot.setWidth(canvasXSize); 15 | plot.setHeight(canvasYSize); 16 | } 17 | 18 | function resetCurvesIdsList() { 19 | 'use strict'; 20 | var select = document.getElementById("curvesIds"); 21 | if (select.hasChildNodes()) { 22 | while (select.childNodes.length > 0) { 23 | select.removeChild(select.firstChild); 24 | } 25 | } 26 | var option = document.createElement('option'); 27 | option.text = "New"; 28 | select.appendChild(option); 29 | 30 | var ids = plot.getCurvesIds(); 31 | var i; 32 | for (i = 0; i < ids.length; i++) { 33 | option = document.createElement('option'); 34 | option.setAttribute('value', ids[i]); 35 | option.text = ids[i]; 36 | select.appendChild(option); 37 | } 38 | } 39 | 40 | function selectCurve(id) { 41 | 'use strict'; 42 | var select = document.getElementById("curvesIds"); 43 | 44 | var i; 45 | for (i = 0; i < select.length; i++) { 46 | if (id === select.item(i).value) { 47 | select.item(i).selected = 'selected'; 48 | } 49 | } 50 | } 51 | 52 | function changeLineProperty(elementId, property, isMarker) { 53 | 'use strict'; 54 | var id = document.getElementById("curvesIds").value; 55 | if (id === 'new') { 56 | return; 57 | } 58 | var value = document.getElementById(elementId).value; 59 | 60 | plot.setCurveProperty(id, property, value); 61 | if (property === 'id') { 62 | resetCurvesIdsList(); 63 | selectCurve(value); 64 | } 65 | } 66 | 67 | function changeMarkerProperty(elementId, property, isMarker) { 68 | 'use strict'; 69 | var id = document.getElementById("curvesIds").value; 70 | if (id === 'new') { 71 | return; 72 | } 73 | var value = document.getElementById(elementId).value; 74 | plot.setCurveMarkerProperty(id, property, value); 75 | } 76 | 77 | function remove() { 78 | 'use strict'; 79 | var id = document.getElementById("curvesIds").value; 80 | if (id === 'new') { 81 | return; 82 | } 83 | plot.remove(id); 84 | resetCurvesIdsList(); 85 | } 86 | 87 | function restart() { 88 | 'use strict'; 89 | plot.clear(); 90 | plot.setTitle('', '', ''); 91 | } 92 | 93 | function setTitle() { 94 | 'use strict'; 95 | var title = document.getElementById("title"); 96 | plot.setTitle(title.value); 97 | } 98 | 99 | function setXLabel() { 100 | 'use strict'; 101 | var xLabel = document.getElementById("xLabel"); 102 | plot.setXLabel(xLabel.value); 103 | } 104 | 105 | function setYLabel() { 106 | 'use strict'; 107 | var yLabel = document.getElementById("yLabel"); 108 | plot.setYLabel(yLabel.value); 109 | } 110 | 111 | function setDisplayTicks() { 112 | 'use strict'; 113 | var select = document.getElementById("displayTicks"); 114 | plot.setOwnProperty('ticks-display', select.value === 'yes' ? true : false); 115 | } 116 | 117 | function setDisplayAxis() { 118 | 'use strict'; 119 | var select = document.getElementById("displayAxis"); 120 | plot.setOwnProperty('axis-display', select.value); 121 | } 122 | 123 | function setPreserveRatio() { 124 | 'use strict'; 125 | var select = document.getElementById("preserveRatio"); 126 | plot.setOwnProperty('preserve-ratio', select.value === 'yes' ? true : false); 127 | } 128 | 129 | function setWidth() { 130 | 'use strict'; 131 | var text = document.getElementById("width"); 132 | plot.setWidth(text.value); 133 | } 134 | 135 | function setHeight() { 136 | 'use strict'; 137 | var text = document.getElementById("height"); 138 | plot.setHeight(text.value); 139 | } 140 | 141 | function addChromaticityDiagram() { 142 | 'use strict'; 143 | var select = document.getElementById("chromaticityDiagram"); 144 | plot.addChromaticityDiagram(select.value); 145 | resetCurvesIdsList(); 146 | } 147 | 148 | function setLegend() { 149 | 'use strict'; 150 | var select = document.getElementById("displayLegend"); 151 | plot.setOwnProperty('legend-display', select.value); 152 | } 153 | 154 | 155 | function getPathProperties() { 156 | 'use strict'; 157 | var properties = {}; 158 | var nPlot = plot.getOwnProperty('auto-id-number'); 159 | if ($('lineStrokeColor').value !== 'auto') { 160 | properties.stroke = $('lineStrokeColor').value; 161 | } 162 | 163 | if ($('markerShape').value !== 'none') { 164 | properties.marker = {}; 165 | properties.marker.shape = $('markerShape').value; 166 | properties.marker.size = $('markerSize').value; 167 | if ($('markerFillColor').value !== 'auto') { 168 | properties.marker.fill = $('markerFillColor').value; 169 | } 170 | properties.marker.stroke = 'none'; 171 | } 172 | 173 | properties['stroke-dasharray'] = $('lineStyle').value; 174 | properties['stroke-width'] = $('lineWidth').value; 175 | 176 | return properties; 177 | } 178 | 179 | var print = function () { 180 | $('default-plot').getPlot().print(); 181 | }; 182 | 183 | var DATA = []; 184 | 185 | window.onload = function () { 186 | 'use strict'; 187 | var fieldsets = initFieldset(); 188 | fieldsets.hideAll(); 189 | 190 | plot = new Plot('default-plot', [512, 512], 'image'); 191 | 192 | var read = function (evt) { 193 | var callback = function (evt, type) { 194 | switch (type) { 195 | case 'url': 196 | filesData.push(this); 197 | plot.addImage(this); 198 | resetCurvesIdsList(); 199 | break; 200 | case 'txt': 201 | filesData.push(this); 202 | var auto = $('lineStrokeColor').value === 'auto' || $('markerFillColor').value === 'auto'; 203 | DATA.push(this); 204 | plot.displayCsv(this, undefined, auto, getPathProperties()); 205 | resetCurvesIdsList(); 206 | break; 207 | default: 208 | throw new Error(file.type); 209 | } 210 | }; 211 | 212 | // Only call the handler if 1 or more files was dropped. 213 | if (this.files.length) { 214 | var i; 215 | for (i = 0; i < this.files.length; i++) { 216 | readFile(this.files[i], callback); 217 | } 218 | } 219 | }; 220 | 221 | $("loadFile").addEventListener("change", read, false); 222 | 223 | // Tools.makeDraggable(document, callback); 224 | plot.click = function (coord, event) { 225 | if (!this.getOwnProperty('compute-closest')) { 226 | return; 227 | } 228 | var c = this.getClosestPoint(coord.x, coord.y, false); 229 | if (c) { 230 | console.log('Selected point: ' + c.x + ', ' + c.y); 231 | plot.setCursor(c.x, c.y); 232 | selectCurve(c.data.getAttributeNS(null, 'id')); 233 | } 234 | }; 235 | updateOutput(); 236 | document.body.onresize = updateOutput; 237 | 238 | } 239 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JSM 2 | === 3 | 4 | # The JavaScript Matrix Library 5 | 6 | This library intends to provide an easy way to deal with nd-array. This implementation has many advantages since 7 | * it use typed array for fast computation and controled memory comsumption ; 8 | * parameters consistency is well checked ; 9 | * design allows it to work with real as well as complex values ; 10 | * it is easy to use thanks to the object notation. 11 | 12 | Many modules are developed 13 | * for nd-array manipulation including value selection and modifications ; 14 | * for arithmetic and boolean operation ; 15 | * for linear algebra ; 16 | * for image processing, such as filtering, FFT, image matching ; 17 | * for statistical processing ; ... 18 | 19 | A list of supported functions (not necessarily up to date) may be found [here](http://etsitpab.github.io/JSM/#!/guide/functions). A brief introduction is available [here](https://github.com/Etsitpab/JSM/blob/master/doc/guides/getting_started/README.md). 20 | 21 | The inspiration is the well known [Matlab][1] software though there are some differences in the syntax we used. 22 | 23 | [1]:http://www.mathworks.fr/products/matlab/ 24 | 25 | # [Documentation](http://etsitpab.github.io/JSM/) and demos 26 | The documentation can be consulted [here](http://etsitpab.github.io/JSM/). The code is documented using [jsduck](https://github.com/senchalabs/jsduck). Once it is installed just use the command `make doc` 27 | If you experience problem, be sure that you installed the ruby1.9-dev (or more recent) package and check this [page](https://github.com/senchalabs/jsduck/wiki/Installation). 28 | 29 | Here are links to some demos that have been realized with this project. _Note that they have been tested on Firefox and Google Chrome, and not with other browsers. Please be careful as well with large images, they might require large amount of memory and processing might take a lot of time !_ 30 | 31 | - [Estimation of illuminants from projections on the planckian locus and other color constancy algorithms](http://etsitpab.github.io/JSM/examples/ppl/ppl.html) 32 | - [Color Enhancement in the Wavelet domain](http://etsitpab.github.io/JSM/examples/colorenhancement/demo.html) 33 | - [Image editor](http://etsitpab.github.io/JSM/examples/colorspaces/colorspaces.html) (Beta version) 34 | - [Plot editor](http://etsitpab.github.io/JSM/examples/plot/plot-editor.html) (Beta version) 35 | - [Game of life](http://etsitpab.github.io/JSM/examples/gameoflife/gameoflife.html) (Beta version) 36 | - [Keypoint detector](http://etsitpab.github.io/JSM/examples/keypoints/keypoints.html) (Beta version) 37 | - [Image matching with local descriptors](http://etsitpab.github.io/JSM/examples/sift/sift.html) (Alpha version) 38 | - [A contrario histogram modes detection](http://etsitpab.github.io/JSM/examples/modes/modes.html) (Alpha version) 39 | 40 | 41 | 42 | # How to compile and test it 43 | 44 | ## Compilation 45 | 46 | In order to regenerate the modules from the sources, you simply need to use the command `make` (Unix system). 47 | To minify the modules and the projects, you have to install [uglifyjs](https://github.com/mishoo/UglifyJS2). Once it's done, just enter `make minify`. 48 | 49 | ## Test 50 | 51 | To test it, just download the modules that you need, they are located in the `./modules/` directory. 52 | The core module is `JSM.js` and it is the concatenation of the `Matrix.js`, `Matrix.js` and `Tools.js` modules. The other modules such that `Plot.js` and `Matching.js` are independent. 53 | In the directory `./min/` you can find the minified version of the modules. 54 | 55 | ## Nodejs and npm 56 | 57 | There is not yet a specific package that can be install with `npm` but the modules `JSM.js` and `JSM.min.js` can be imported in nodejs script by using one of these instruction : 58 | - `var JSM = require('.//module/JSM.js');` ; 59 | - `var JSM = require('.//min/JSM.min.js');`. 60 | 61 | To be able to read and write images you have to install npm canvas package. To this end, ensure that the following packages are installed (on Ubuntu/Debian) : 62 | - node-legacy 63 | - libcairo2-dev 64 | - libgif-dev 65 | - libjpeg8-dev / libjpeg9-dev 66 | - libpango1.0-dev 67 | 68 | Also, do not forget to add the path to nodejs modules, it should look like that : 69 | `export NODE_PATH="/usr/local/lib/node_modules"` 70 | 71 | 72 | # Why develop a JavaScript library for numerical computing ? 73 | 74 | Many reasons can justify this. First, JavaScript is fun. It's easy too use and it has very powerful features (closures, prototype, ...). 75 | Also, put it together with HTML and CSS and you have a perfect team to build great and very efficient UIs. 76 | For research purpose, it allows to make online demonstrations which can be used directly in the browser. 77 | 78 | More and more web applications request to deal with numerical data, and we do not found a library providing a complete and robust JavaScript framework to do it. 79 | 80 | # Other JavaScript libraries for numerical computation 81 | 82 | Here comes a list made of JS library that we found interesting. 83 | This list does not pretend to exhaustive and if you would like to see a link to your website added here please send an email. 84 | 85 | - [mathjs](http://mathjs.org/) 86 | - [jStat](https://github.com/jstat/jstat) 87 | - [jsmat](https://github.com/ghewgill/jsmat) 88 | - [JSNum](https://github.com/kms15/jsnum) 89 | - [Numeric JavaScript](http://numericjs.com/numeric/documentation.html) 90 | - [Sylvester](http://sylvester.jcoglan.com/) 91 | - [jsfeat](http://inspirit.github.io/jsfeat/) 92 | 93 | # Content of the JSM project 94 | 95 | ./ 96 | +- doc/ 97 | | + jsduck.json - doc. configuration file 98 | | + guides.json - tutorials configuration file 99 | | +- html/ - generated documentation (HTML format) 100 | | | + index.html - main page of the documentation 101 | | +- content/ - doc. content (raw) 102 | | | + readme.md - content of the doc. main page 103 | | +- tag/ - custom tags definitions 104 | +- examples/ - examples of use of the Matrix class 105 | +- modules/ - modules grouping files together 106 | | + JSM.js - standalone source file, containing all the JS code for the Matrix class 107 | | + .js - others modules/projects minified 108 | +- min/ - minify versions of the Matrix class and related 109 | | + JSM.min.js - standalone source file, containing all the JS code for the Matrix class 110 | | + .min.js - other module projects files minified 111 | +- projects/ - projects making use of the Matrix class 112 | +- src/ - source files 113 | | +- Matrix - Matrix JavaScript class, split into several files 114 | | +- MatrixView - MatrixView JavaScript class, split into several files 115 | | +- Tools - Tools JavaScript object, split into several files 116 | | +- - Other modules 117 | +- third/ - used to store third part projects 118 | + licence.txt - short licence description, included in JS files 119 | + Makefile - Makefile used to generate documentation, minified files and lint 120 | -------------------------------------------------------------------------------- /src/Matrix/Matrix.numeric_types.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | * 15 | * @author Baptiste Mazin 16 | * @author Guillaume Tartavel 17 | */ 18 | 19 | /** @class Matrix */ 20 | 21 | (function (Matrix, Matrix_prototype) { 22 | "use strict"; 23 | 24 | /** Returns a new Matrix with a data cast. 25 | * 26 | * __Also see:__ 27 | * {@link Matrix#type}. 28 | * 29 | * @return {Matrix} 30 | * 31 | * @matlike 32 | */ 33 | Matrix_prototype.cast = function (Type) { 34 | var flag; 35 | switch (Type.toLowerCase()) { 36 | case 'boolean': 37 | case 'bool': 38 | case "logical": 39 | flag = true; 40 | break; 41 | default: 42 | flag = false; 43 | } 44 | 45 | Type = Tools.checkType(Type); 46 | var od = new Type(this.getData()); 47 | return new Matrix(this.getSize(), od, !this.isreal(), flag); 48 | }; 49 | 50 | /** Converts a Matrix to double. 51 | * 52 | * __Also see:__ 53 | * {@link Matrix#cast}. 54 | * 55 | * @return {Matrix} 56 | * 57 | * @matlike 58 | */ 59 | Matrix_prototype.double = function () { 60 | return this.cast('double'); 61 | }; 62 | 63 | /** Converts a Matrix to single. 64 | * 65 | * __Also see:__ 66 | * {@link Matrix#cast}. 67 | * 68 | * @return {Matrix} 69 | * 70 | * @matlike 71 | */ 72 | Matrix_prototype.single = function () { 73 | return this.cast('single'); 74 | }; 75 | 76 | /** Converts a Matrix to int8. 77 | * 78 | * Also see {@link Matrix#cast}. 79 | * 80 | * @return {Matrix} 81 | * 82 | * @matlike 83 | */ 84 | Matrix_prototype.int8 = function () { 85 | return this.cast('int8'); 86 | }; 87 | 88 | /** Converts a Matrix to int16. 89 | * 90 | * __Also see:__ 91 | * {@link Matrix#cast}. 92 | * 93 | * @return {Matrix} 94 | * 95 | * @matlike 96 | */ 97 | Matrix_prototype.int16 = function () { 98 | return this.cast('int16'); 99 | }; 100 | 101 | /** Converts a Matrix to int32. 102 | * 103 | * __Also see:__ 104 | * {@link Matrix#cast}. 105 | * 106 | * @return {Matrix} 107 | * 108 | * @matlike 109 | */ 110 | Matrix_prototype.int32 = function () { 111 | return this.cast('int32'); 112 | }; 113 | 114 | /** Converts a Matrix to uint8. 115 | * 116 | * __Also see:__ 117 | * {@link Matrix#cast}. 118 | * 119 | * @return {Matrix} 120 | * 121 | * @matlike 122 | */ 123 | Matrix_prototype.uint8 = function () { 124 | return this.cast('uint8'); 125 | }; 126 | 127 | /** Converts a Matrix to logical. 128 | * 129 | * __Also see:__ 130 | * {@link Matrix#cast}. 131 | * 132 | * @return {Matrix} 133 | * 134 | * @matlike 135 | */ 136 | Matrix_prototype.logical = function () { 137 | return this.cast('logical'); 138 | }; 139 | 140 | /** Converts a Matrix to uint8c. 141 | * 142 | * __Also see:__ 143 | * {@link Matrix#cast}. 144 | * 145 | * @return {Matrix} 146 | */ 147 | Matrix_prototype.uint8c = function () { 148 | return this.cast('uint8c'); 149 | }; 150 | 151 | /** Converts a Matrix to uint16. 152 | * 153 | * __Also see:__ 154 | * {@link Matrix#cast}. 155 | * 156 | * @return {Matrix} 157 | * 158 | * @matlike 159 | */ 160 | Matrix_prototype.uint16 = function () { 161 | return this.cast('uint16'); 162 | }; 163 | 164 | /** Converts a Matrix to uint32. 165 | * 166 | * __Also see:__ 167 | * {@link Matrix#cast}. 168 | * 169 | * @return {Matrix} 170 | * 171 | * @matlike 172 | */ 173 | Matrix_prototype.uint32 = function () { 174 | return this.cast('uint32'); 175 | }; 176 | 177 | /** Returns a logical Matrix with 1 if value is NaN and 0 otherwise. 178 | * 179 | * @return {Matrix} 180 | * 181 | * @matlike 182 | */ 183 | Matrix_prototype.isnan = function () { 184 | var oMat = new Matrix(this.getSize(), 'logical'); 185 | var od = oMat.getData(); 186 | var i, ie; 187 | if (this.isreal()) { 188 | var id = this.getData(); 189 | for (i = 0, ie = od.length; i < ie; i++) { 190 | od[i] = isNaN(id[i]); 191 | } 192 | } else { 193 | var ird = this.getRealData(), iid = this.getImagData(); 194 | for (i = 0, ie = od.length; i < ie; i++) { 195 | od[i] = isNaN(ird[i]) || isNaN(iid[i]); 196 | } 197 | } 198 | return oMat; 199 | }; 200 | 201 | /** Returns a logical Matrix with 1 if value is NaN and 0 otherwise. 202 | * 203 | * @return {Matrix} 204 | * 205 | * @matlike 206 | */ 207 | Matrix_prototype.isinf = function () { 208 | var oMat = new Matrix(this.getSize(), 'logical'); 209 | var od = oMat.getData(); 210 | var i, ie; 211 | if (this.isreal()) { 212 | var id = this.getData(); 213 | for (i = 0, ie = od.length; i < ie; i++) { 214 | var v = id[i]; 215 | od[i] = (v === Infinity) || (v === -Infinity) ? 1 : 0; 216 | } 217 | } else { 218 | var ird = this.getRealData(), iid = this.getImagData(); 219 | for (i = 0, ie = od.length; i < ie; i++) { 220 | var vr = ird[i], vi = iid[i]; 221 | od[i] = ((vr === Infinity) || (vr === -Infinity) || 222 | (vi === Infinity) || (vi === -Infinity)) ? 1 : 0; 223 | } 224 | } 225 | return oMat; 226 | }; 227 | 228 | /** Returns a logical Matrix with 1 if value is NaN and 0 otherwise. 229 | * 230 | * @return {Matrix} New Matrix. 231 | * 232 | * @matlike 233 | */ 234 | Matrix_prototype.isfinite = function () { 235 | var oMat = new Matrix(this.getSize(), 'logical'); 236 | var od = oMat.getData(); 237 | var i, ie; 238 | if (this.isreal()) { 239 | var id = this.getData(); 240 | for (i = 0, ie = od.length; i < ie; i++) { 241 | od[i] = isFinite(id[i]) ? 1 : 0; 242 | } 243 | } else { 244 | var ird = this.getRealData(), iid = this.getImagData(); 245 | for (i = 0, ie = od.length; i < ie; i++) { 246 | od[i] = (isFinite(ird[i]) || isFinite(iid[i])) ? 1 : 0; 247 | } 248 | } 249 | return oMat; 250 | }; 251 | 252 | })(Matrix, Matrix.prototype); 253 | -------------------------------------------------------------------------------- /examples/common/Webcam.class.js: -------------------------------------------------------------------------------- 1 | /*jslint nomen: true, vars: true, plusplus: true, bitwise: true, browser: true, devel: true */ 2 | /*global URL, MediaStreamTrack */ 3 | 4 | /** @class FileLoader 5 | * @author Guillaume Tartavel 6 | * A simple webcam interface. 7 | */ 8 | 9 | /* Change log 10 | * 2015-07-14: first version 11 | */ 12 | 13 | /** @constructor 14 | * @param {String} name 15 | * @param {String} id 16 | * @private */ 17 | function Webcam(name, id) { 18 | 'use strict'; 19 | /** Name of the camera. @type {String} */ 20 | this.name = name || 'unnamed'; 21 | 22 | /** ID of the camera. @readonly @type {String} */ 23 | this.id = id || null; 24 | 25 | /** Width of the video, when ready. @readonly @type {Number} */ 26 | this.width = 0; 27 | 28 | /** Height of the video, when ready. @readonly @type {Number} */ 29 | this.height = 0; 30 | 31 | /** Status of the camera, can be STOPPED, PLAYING, or PAUSED constants. @readonly @type {Number} */ 32 | this.status = Webcam.STOPPED; 33 | 34 | /** Video element on which the camera is played. @readonly @type {HTMLElement} */ 35 | this.videoElement = document.createElement('video'); 36 | this.videoElement.autoplay = true; 37 | 38 | /** The webcam stream. @private @type {Mixed} */ 39 | this._stream = null; 40 | 41 | // Setup listeners 42 | Webcam._initEventListeners(this); 43 | 44 | return this; 45 | } 46 | 47 | /** Constant for "stopped" status. @readonly @static @type {Number} */ 48 | Webcam.STOPPED = 0; 49 | /** Constant for "playing" status. @readonly @static @type {Number} */ 50 | Webcam.PLAYING = 1; 51 | /** Constant for "paused" status. @readonly @static @type {Number} */ 52 | Webcam.PAUSED = -1; 53 | 54 | 55 | /** Initialize the listeners of a Webcam. 56 | * @param {Webcam} that 57 | * @static @private */ 58 | Webcam._initEventListeners = function (that) { 59 | 'use strict'; 60 | that.videoElement.addEventListener('canplaythrough', function () { 61 | that.width = that.videoElement.width = that.videoElement.videoWidth; 62 | that.height = that.videoElement.height = that.videoElement.videoHeight; 63 | that.onready(); 64 | }); 65 | }; 66 | 67 | /** List the available Webcams. 68 | * In case listing is not possible, the standard Webcam.std will be used instead. 69 | * @param {Function} callback 70 | * Function to be called once the list is available. 71 | * Takes a Webcam array as argument. 72 | * @static */ 73 | Webcam.list = function(callback) { 74 | 'use strict'; 75 | if (!MediaStreamTrack || !MediaStreamTrack.getSources) { 76 | callback([Webcam.std]); 77 | return; 78 | } 79 | MediaStreamTrack.getSources(function(srcs) { 80 | var k, list = []; 81 | for (k = 0; k < srcs.length; ++k) { 82 | if (srcs[k].kind === 'video') { 83 | list.push(new Webcam(srcs[k].label || srcs[k].facing, srcs[k].id)); 84 | } 85 | } 86 | callback(list); 87 | }); 88 | }; 89 | 90 | /** Apply a function to each available Webcam. 91 | * @param {Function} callback 92 | * Function to be applied to each Webcam. 93 | * Takes the Webcam object as first argument. 94 | * Takes the number of available Webcams as second argument. 95 | * @static */ 96 | Webcam.forEach = function(callback) { 97 | 'use strict'; 98 | Webcam.list(function (result) { 99 | result.forEach(function (webcam) { 100 | callback(webcam, result.length); 101 | }) 102 | }); 103 | }; 104 | 105 | /** Fired when the Webcam is ready to play (metadata are available). 106 | * @event */ 107 | Webcam.prototype.onready = function () { 108 | 'use strict'; 109 | return; 110 | }; 111 | 112 | /** Start the Webcam, or restart it if already launched. 113 | * @param {Function} [errorCallback] 114 | * Callback if the Webcam cannot be launched. 115 | * Takes the Error element as parameter. 116 | */ 117 | Webcam.prototype.start = function (errorCallback) { 118 | 'use strict'; 119 | var that = this; 120 | var opts = {'optional': [{'sourceId': this.id}] }; 121 | this.stop(); 122 | navigator.getUserMedia( 123 | { 124 | 'audio': false, 125 | 'video': this.id ? opts : true 126 | }, 127 | function (stream) { 128 | that.videoElement.src = URL ? URL.createObjectURL(stream) : stream; 129 | that._stream = stream; 130 | that.status = Webcam.PLAYING; 131 | }, 132 | errorCallback || function (error) { 133 | throw new Error('Cannot launch the webcam (' + error.name + ')'); 134 | } 135 | ); 136 | }; 137 | 138 | /** Stop the Webcam. */ 139 | Webcam.prototype.stop = function () { 140 | 'use strict'; 141 | if (this._stream) { 142 | this._stream.stop(); 143 | this._stream = null; 144 | this.status = Webcam.STOPPED; 145 | } 146 | }; 147 | 148 | /** Pause the Webcam. */ 149 | Webcam.prototype.pause = function () { 150 | 'use strict'; 151 | if (this.status === Webcam.PLAYING) { 152 | this.videoElement.pause(); 153 | this.status = Webcam.PAUSED; 154 | } 155 | }; 156 | 157 | /** Resume the Webcam if paused. Does nothing if the Webcam was stopped. 158 | * @return {Boolean} 159 | * `true` iff the Webcam is now playing. 160 | */ 161 | Webcam.prototype.resume = function () { 162 | 'use strict'; 163 | if (this.status === Webcam.PAUSED) { 164 | this.videoElement.play(); 165 | this.status = Webcam.PLAYING; 166 | return true; 167 | } 168 | return (this.status === Webcam.PLAYING); 169 | }; 170 | 171 | /** Extract the current frame to a canvas. 172 | * @param {HTMLElement} [outCanvas] 173 | * The canvas to store the picture to. 174 | * @return {HTMLElement} 175 | * The canvas containing the snapshot, or `null` if no image available. 176 | */ 177 | Webcam.prototype.snapshot = function (outCanvas) { 178 | 'use strict'; 179 | var canvas = outCanvas || document.createElement('canvas'); 180 | var ctx = canvas.getContext('2d'); 181 | if (!ctx) { 182 | return null; 183 | } 184 | canvas.width = this.width; 185 | canvas.height = this.height; 186 | ctx.drawImage(this.videoElement, 0, 0, this.width, this.height); 187 | return canvas; 188 | }; 189 | 190 | // For portability 191 | (function () { 192 | 'use strict'; 193 | window.URL = (window.URL || window.webkitURL || window.mozURL || window.msURL); 194 | navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia 195 | || navigator.mozGetUserMedia || navigator.msGetUserMedia); 196 | 197 | }()); 198 | 199 | /** Request a function to be run (synchronize it with the next frame repaint). 200 | * @param {Function} callback 201 | * Function requested to be run ASAP. 202 | */ 203 | Webcam.requestAnimationFrame = (function () { 204 | 'use strict'; 205 | var f = window.requestAnimationFrame 206 | || window.webkitRequestAnimationFrame 207 | || window.mozRequestAnimationFrame 208 | || window.oRequestAnimationFrame 209 | || window.msRequestAnimationFrame 210 | || function(callback) { window.setTimeout(callback, 1000 / 60); }; 211 | return function (arg) { 212 | f.call(window, arg); 213 | }; 214 | }()); 215 | 216 | /** Standard Webcam (the default one). @readonly @static @type {Webcam} */ 217 | Webcam.std = new Webcam('default'); 218 | 219 | /** Is `true` iff the webcams can be listed. @readonly @static @type {Boolean} */ 220 | Webcam.listable = Boolean(MediaStreamTrack && MediaStreamTrack.getSources); 221 | -------------------------------------------------------------------------------- /examples/sift/sift.js: -------------------------------------------------------------------------------- 1 | /*global console, document, Matrix, Colorspaces, CIE, open */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | 4 | 5 | var IMAGES = [], NAMES = [], S, VIEW, WIN; 6 | function exportAll() { 7 | var imName1 = NAMES[0].match(/(.*)\.[^.]+$/)[1], 8 | imName2 = NAMES[1].match(/(.*)\.[^.]+$/)[1], 9 | s; 10 | s = S.scaleSpaces[0]; 11 | Tools.stringToDownload(s.keypointsToString(), imName1 + "_descriptors_keypoints.txt"); 12 | Tools.stringToDownload(s.descriptorsToString("SIFT"), imName1 + "_descriptors_SIFT.txt"); 13 | Tools.stringToDownload(s.descriptorsToString("HUE-NORM"), imName1 + "_descriptors_HUE-NORM.txt"); 14 | Tools.stringToDownload(s.descriptorsToString("OHTA1"), imName1 + "_descriptors_OHTA1.txt"); 15 | Tools.stringToDownload(s.descriptorsToString("OHTA2"), imName1 + "_descriptors_OHTA2.txt"); 16 | 17 | s = S.scaleSpaces[1]; 18 | Tools.stringToDownload(s.keypointsToString(), imName2 + "_keypoints.txt"); 19 | Tools.stringToDownload(s.descriptorsToString("SIFT"), imName2 + "_descriptors_SIFT.txt"); 20 | Tools.stringToDownload(s.descriptorsToString("HUE-NORM"), imName2 + "_descriptors_HUE-NORM.txt"); 21 | Tools.stringToDownload(s.descriptorsToString("OHTA1"), imName2 + "_descriptors_OHTA1.txt"); 22 | Tools.stringToDownload(s.descriptorsToString("OHTA2"), imName2 + "_descriptors_OHTA2.txt"); 23 | 24 | var value, name; 25 | value = "SIFT"; 26 | name = imName1 + "_" + imName2 + "_matches_" + value + ".txt"; 27 | Tools.stringToDownload(S.matchesToString(0, 1, value), name); 28 | value = "SIFT+HUE-Norm"; 29 | name = imName1 + "_" + imName2 + "_matches_" + value + ".txt"; 30 | Tools.stringToDownload(S.matchesToString(0, 1, value), name); 31 | value = "Ohta-SIFT"; 32 | name = imName1 + "_" + imName2 + "_matches_" + value + ".txt"; 33 | Tools.stringToDownload(S.matchesToString(0, 1, value), name); 34 | value = "Ohta-SIFT+HUE-Norm"; 35 | name = imName1 + "_" + imName2 + "_matches_" + value + ".txt"; 36 | Tools.stringToDownload(S.matchesToString(0, 1, value), name); 37 | 38 | } 39 | 40 | function exportData() { 41 | "use strict"; 42 | var n = this.id === "export1" ? 0 : 1, 43 | s = S.scaleSpaces[n], value = $V(this.id), 44 | str = "", name, 45 | imName = NAMES[n].match(/(.*)\.[^.]+$/)[1]; 46 | switch (value) { 47 | case "keypoints": 48 | name = imName + "_keypoints.txt"; 49 | str = s.keypointsToString(); 50 | break; 51 | default: 52 | name = imName + "_descriptors_" + value + ".txt"; 53 | str = s.descriptorsToString(value); 54 | } 55 | Tools.stringToDownload(str, name); 56 | } 57 | 58 | function exportMatches() { 59 | "use strict"; 60 | var value = $V(this.id), 61 | name1 = NAMES[0].match(/(.*)\.[^.]+$/)[1], 62 | name2 = NAMES[1].match(/(.*)\.[^.]+$/)[1], 63 | str = S.matchesToString(0, 1, value), 64 | name = name1 + "_" + name2 + "_matches_" + value + ".txt"; 65 | Tools.stringToDownload(str, name); 66 | } 67 | 68 | function updateOutput(image) { 69 | "use strict"; 70 | var outputCanvas = $("outputImage"), 71 | div = $("image"), 72 | canvasXSize = div.offsetWidth, 73 | canvasYSize = div.offsetHeight; 74 | outputCanvas.width = canvasXSize; 75 | outputCanvas.height = canvasYSize; 76 | image.imshow(outputCanvas, "fit"); 77 | outputCanvas.style.marginTop = (div.offsetHeight - outputCanvas.height) / 2; 78 | } 79 | 80 | var readFile = function (file, callback, type) { 81 | // Deal with arguments 82 | type = type.toLowerCase(); 83 | 84 | // File handling functions 85 | var reader = new FileReader(); 86 | reader.onload = function (evt) { 87 | callback = callback.bind(evt.target.result); 88 | callback(evt); 89 | }; 90 | 91 | switch (type) { 92 | case 'dataurl': 93 | case 'url': 94 | reader.readAsDataURL(file); 95 | break; 96 | case 'text': 97 | case 'txt': 98 | reader.readAsText(file); 99 | break; 100 | case 'arraybuffer': 101 | case 'binary': 102 | case 'bin': 103 | reader.readAsArrayBuffer(file); 104 | break; 105 | default: 106 | throw new Error("readFile: unknown type " + type + "."); 107 | } 108 | }; 109 | 110 | var run = function() { 111 | console.log('loaded !'); 112 | var ds = [ 113 | Matching.descriptorDB['SIFT'], 114 | //Matching.descriptorDB['HUE-NORM'], 115 | Matching.descriptorDB['OHTA1'], 116 | Matching.descriptorDB['OHTA2'] 117 | ]; 118 | var combinations = { 119 | "SIFT": ["SIFT"], 120 | //"SIFT+HUE-Norm": ["SIFT", "HUE-NORM"], 121 | "Ohta-SIFT": ["SIFT", "OHTA1", "OHTA2"], 122 | // "Ohta-SIFT+HUE-Norm": ["SIFT", "OHTA1", "OHTA2", "HUE-NORM"] 123 | }; 124 | var computeSift = function () { 125 | Matching.Descriptor.prototype.distance = $("distance").value; 126 | Matching.Keypoint.prototype.descriptors = ds; 127 | Matching.Keypoint.prototype.criterion = "NN-DR"; 128 | Matching.ScaleSpace.prototype.harrisThresh = $F("harris"); 129 | 130 | var mat, proj = false; 131 | if (IMAGES.length === 1) { 132 | IMAGES = IMAGES[0]; 133 | mat = Matching.getSkewMatrix(IMAGES, $F('matrix')); 134 | proj = true; 135 | mat.display(); 136 | } 137 | 138 | // console.profile(); 139 | S = Matching.benchmark(IMAGES, mat, function () {return this;}, proj, {}, combinations); 140 | 141 | 142 | VIEW = S.createView($("image")); 143 | VIEW.thresholdMatches(parseFloat($("threshold").value), $V("combination")); 144 | 145 | } 146 | computeSift(); 147 | var changeThreshold = function () { 148 | VIEW.thresholdMatches(parseFloat($V("threshold")), $V("combination")); 149 | }; 150 | 151 | var changeDistance = function () { 152 | Matching.Descriptor.prototype.distance = $("distance").value; 153 | S.computeDescriptors(ds); 154 | VIEW.computeMatches(this.value.split(','), parseFloat($("threshold").value)); 155 | VIEW.thresholdMatches(parseFloat(this.value)); 156 | }; 157 | 158 | $("threshold").addEventListener("change", changeThreshold); 159 | $("combination").addEventListener("change", changeThreshold); 160 | $("distance").addEventListener("change", changeDistance); 161 | $("export1").addEventListener("change", exportData); 162 | $("export2").addEventListener("change", exportData); 163 | $("export3").addEventListener("change", exportMatches); 164 | }; 165 | 166 | window.onload = function () { 167 | "use strict"; 168 | 169 | var inputs = document.getElementsByTagName('input'); 170 | var focus = function () { 171 | this.focus(); 172 | }; 173 | var i; 174 | for (i = 0; i < inputs.length; i++) { 175 | if (inputs[i].type == 'range') { 176 | inputs[i].addEventListener('click', focus); 177 | } 178 | } 179 | var read = function (evt) { 180 | 181 | var files = this.files; 182 | 183 | var callback = function (evt) { 184 | var onread = function () { 185 | IMAGES.push(limitImageSize(this, 600)); 186 | if (IMAGES.length === files.length) { 187 | run(); 188 | } 189 | }; 190 | Matrix.imread(this, onread); 191 | }; 192 | // Only call the handler if 1 or more files was dropped. 193 | if (files.length > 0 && files.length < 3) { 194 | IMAGES = []; 195 | var i; 196 | for (i = 0; i < files.length; i++) { 197 | NAMES[i] = files[i].name; 198 | readFile(files[i], callback, "url"); 199 | } 200 | } 201 | 202 | }; 203 | $("loadFile").addEventListener("change", read, false); 204 | 205 | var fieldsets = initFieldset(); 206 | fieldsets.hideAll(); 207 | }; 208 | -------------------------------------------------------------------------------- /examples/keypoints/keypoints.js: -------------------------------------------------------------------------------- 1 | /*global console, document, Matrix, Colorspaces, CIE, open, ScaleSpace, extractModes, Blob, URL, $, $F, $I, window */ 2 | /*jshint indent: 4, unused: true, white: true */ 3 | var IMAGE, SCALESPACE, KNUM, sCanvas; 4 | 5 | function exportImage() { 6 | "use strict"; 7 | open(sCanvas.images[0].toDataURL()); 8 | } 9 | 10 | function exportKeypoints() { 11 | 'use strict'; 12 | var out = SCALESPACE.keypointsToString(); 13 | var blob = new Blob([out], {type: 'text'}); 14 | var url = URL.createObjectURL(blob); 15 | var a = document.getElementById("export"); 16 | 17 | var textFileAsBlob = new Blob([out], {type: 'text/plain'}); 18 | 19 | var downloadLink = document.createElement("a"); 20 | downloadLink.download = "keypoints.txt"; 21 | downloadLink.innerHTML = "Download File"; 22 | downloadLink.href = URL.createObjectURL(textFileAsBlob); 23 | downloadLink.click(); 24 | } 25 | 26 | 27 | function updateOutput(image) { 28 | "use strict"; 29 | sCanvas.displayImage(image, 0, true); 30 | } 31 | 32 | HTMLCanvasElement.prototype.plotKeypoint = function (k, ring, orientation, color1, color2) { 33 | "use strict"; 34 | var context = this.getContext('2d'); 35 | var sin = Math.sin, cos = Math.cos; 36 | var drawArrow = function (startX, startY, angle, size) { 37 | angle = (angle > 0.5 ? angle - 1 : angle) * 2 * Math.PI; 38 | this.beginPath(); 39 | this.moveTo(startX, startY); 40 | this.lineTo(startX + size * cos(angle), startY + size * sin(angle)); 41 | this.stroke(); 42 | }.bind(context); 43 | 44 | var drawRing = function (x, y, size) { 45 | this.beginPath(); 46 | this.arc(x, y, size, 0, 2 * Math.PI, false); 47 | this.arc(x, y, size, 0, 2 * Math.PI, false); 48 | this.stroke(); 49 | }.bind(context); 50 | 51 | var drawPoint = function (x, y) { 52 | this.beginPath(); 53 | this.fillStyle = color2; 54 | this.arc(x, y, 2, 0, 2 * Math.PI, false); 55 | this.fill(); 56 | }.bind(context); 57 | 58 | 59 | 60 | context.strokeStyle = "black"; 61 | context.fillStyle = "black"; 62 | context.lineWidth = 3; 63 | if (ring) { 64 | drawRing(k.x, k.y, k.sigma * k.factorSize); 65 | } 66 | if (orientation) { 67 | drawArrow(k.x, k.y, k.orientation, k.sigma * k.factorSize); 68 | } 69 | drawPoint(k.x, k.y); 70 | 71 | color1 = color2 || color1 || "magenta"; 72 | color1 = color1 || "lime"; 73 | context.strokeStyle = color1; 74 | context.fillStyle = color1; 75 | context.lineWidth = 1; 76 | if (ring) { 77 | drawRing(k.x, k.y, k.sigma * k.factorSize); 78 | } 79 | if (orientation) { 80 | drawArrow(k.x, k.y, k.orientation, k.sigma * k.factorSize); 81 | } 82 | drawPoint(k.x, k.y); 83 | return this; 84 | }; 85 | 86 | var plotKeypoints = function (scale, color) { 87 | "use strict"; 88 | if (!SCALESPACE || !SCALESPACE.keypoints) { 89 | //return; 90 | } 91 | var keypoints = SCALESPACE.keypoints; 92 | var canvas = sCanvas.images[0]; 93 | if (scale === true) { 94 | scale = parseInt($("scaleView").value, 10); 95 | } 96 | var i, ei; 97 | for (i = 0, ei = keypoints.length; i < ei; i++) { 98 | if (scale && keypoints[i].nScale !== scale) { 99 | continue; 100 | } 101 | canvas.plotKeypoint(keypoints[i], false, false, color); 102 | } 103 | }; 104 | 105 | var changeImage = function () { 106 | "use strict"; 107 | var scale = parseInt($("scaleView").value, 10); 108 | var filter = $("filter").value; 109 | var cMap = $("colormap").value; 110 | if (!SCALESPACE) { 111 | return; 112 | } 113 | var image; 114 | if (filter !== "blur" && cMap !== "GRAY" && filter !== "hybrid") { 115 | image = SCALESPACE.getImage(scale, filter, true); 116 | image = image.toColormap(cMap); 117 | } else if (filter === "hybrid") { 118 | var norm = SCALESPACE.getImage(scale, "norm", true); 119 | var phase = SCALESPACE.getImage(scale, "phase"); 120 | image = window.phaseNormImage(phase, norm); 121 | } else { 122 | image = SCALESPACE.getImage(scale, filter, true); 123 | } 124 | updateOutput(image); 125 | }; 126 | 127 | var changeView = function () { 128 | "use strict"; 129 | changeImage(); 130 | plotKeypoints(true); 131 | }; 132 | 133 | var changeKeypoint = function () { 134 | "use strict"; 135 | var k = $("keypoint").value, key = SCALESPACE.keypoints[k - 1]; 136 | var h = key.histogram, l = h.lambda; 137 | var modes = extractModes(h, true, 0, h.nPoints, l, l * l); 138 | $("scaleView").value = key.nScale; 139 | changeView(); 140 | sCanvas.images[0].plotKeypoint(key, true, true, "white"); 141 | $("histogram").drawHistogram(h, 0.1, "", modes, true); 142 | }; 143 | 144 | var threshold = function () { 145 | "use strict"; 146 | var lap = parseFloat($("lapThresh").value); 147 | var harris = parseFloat($("harrisThresh").value); 148 | console.log("Threshold:", lap, harris); 149 | if (!SCALESPACE) { 150 | return; 151 | } 152 | SCALESPACE.laplacianThreshold(lap); 153 | SCALESPACE.harrisThreshold(harris); 154 | changeImage(); 155 | plotKeypoints(true); 156 | }; 157 | 158 | var computeOrientations = function () { 159 | "use strict"; 160 | if (!SCALESPACE || !SCALESPACE.keypoints) { 161 | return; 162 | } 163 | threshold(); 164 | var algo = $("orientation").value; 165 | console.log(algo); 166 | SCALESPACE.extractMainOrientations(algo); 167 | var keypoint = $("keypoint"); 168 | keypoint.max = SCALESPACE.keypoints.length; 169 | keypoint.value = 1; 170 | changeKeypoint(); 171 | console.log("Keypoints:", SCALESPACE.keypoints.length); 172 | window.fieldset.hideAll(); 173 | window.fieldset.show("image view"); 174 | }; 175 | 176 | function computeScaleSpace() { 177 | "use strict"; 178 | var sigmaInit = parseFloat($("sigmaInit").value); 179 | var scaleRatio = parseFloat($("scaleRatio").value); 180 | var scaleNumber = parseFloat($("scaleNumber").value); 181 | console.log("Params: ", sigmaInit, scaleRatio, scaleNumber); 182 | $("scaleView").max = scaleNumber - 2; 183 | if (!IMAGE) { 184 | return; 185 | } 186 | SCALESPACE = new Matching.ScaleSpace(IMAGE, scaleNumber, sigmaInit, scaleRatio); 187 | SCALESPACE 188 | .computeScaleSpace() 189 | .precomputeMaxLaplacian() 190 | .precomputeHarris(); 191 | threshold(); 192 | 193 | window.fieldset.hideAll(); 194 | window.fieldset.show("keypoints detection"); 195 | } 196 | 197 | window.onload = function () { 198 | "use strict"; 199 | $("computeScaleSpace").addEventListener("click", computeScaleSpace); 200 | 201 | $("lapThresh").addEventListener("change", threshold); 202 | $("harrisThresh").addEventListener("change", threshold); 203 | 204 | $("scaleView").addEventListener("change", changeView); 205 | $("keypoint").addEventListener("change", changeKeypoint); 206 | $("filter").addEventListener("change", changeView); 207 | $("colormap").addEventListener("change", changeView); 208 | 209 | $("computeOrientations").addEventListener("click", computeOrientations); 210 | 211 | var callback = function (evt) { 212 | var onread = function () { 213 | IMAGE = this.im2single(); 214 | KNUM = undefined; 215 | updateOutput(IMAGE); 216 | // var legends = document.getElementsByTagName("legend"); 217 | // var evObj = document.createEvent('Events'); 218 | // evObj.initEvent("click", true, false); 219 | // fieldset.show("scalespace"); 220 | }; 221 | Matrix.imread(this, onread); 222 | }; 223 | 224 | initFileUpload("loadFile", callback); 225 | initInputs(); 226 | var fieldsets = initFieldset(); 227 | fieldsets.hideAll(); 228 | sCanvas = new SuperCanvas(document.body); 229 | }; 230 | -------------------------------------------------------------------------------- /examples/common/Shortcuts.object.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, nomen: true, bitwise: true, browser: true */ 2 | 3 | /** Provides shortcut definition functions. @singleton */ 4 | var Shortcuts = {}; 5 | 6 | /** Create a shortcut. 7 | * @param {HTMLElement | String} elmt 8 | * Element (or ID) on which the shortcut is active. 9 | * @param {String} shortcut 10 | * Shortcut string, which is a key name (see Shortcuts.KeyNames).
11 | * It can be preceded by modifiers (Alt, Ctrl, Shift) using the `+` symbol.
12 | * Examples: `"F1"`, `"Alt + Tab"`, `"Ctrl+Shift+A"`. 13 | * @param {Function} callback 14 | * Function called when the shortcut is detected. 15 | * The function is called with `this=elmt` and the `KeyboardEvent` as argument. 16 | */ 17 | Shortcuts.create = function (elmt, shortcut, callback) { 18 | 'use strict'; 19 | if (typeof elmt === 'string') { 20 | elmt = document.getElementById(elmt); 21 | } 22 | if (!elmt._shortcuts) { 23 | elmt._shortcuts = {}; 24 | elmt.addEventListener('keydown', Shortcuts._handleEvent); 25 | //elmt.addEventListener('keyup', Shortcuts._handleDefaultPrevention); 26 | //elmt.addEventListener('keypress', Shortcuts._handleDefaultPrevention); 27 | } 28 | var code = Shortcuts._str2code(shortcut); 29 | elmt._shortcuts[code] = callback; 30 | }; 31 | 32 | /** Get a list of shortcuts bound to a given element. 33 | * @param {HTMLElement | String} elmt 34 | * An element or its ID. 35 | * @return {Array} 36 | * Array of shortcuts (as strings) bound to the given element. 37 | */ 38 | Shortcuts.list = function (elmt) { 39 | 'use strict'; 40 | if (typeof elmt === 'string') { 41 | elmt = document.getElementById(elmt); 42 | } 43 | if (!elmt._shortcuts) { 44 | return []; 45 | } 46 | var code, list = []; 47 | for (code in elmt._shortcuts) { 48 | if (elmt._shortcuts.hasOwnProperty(code)) { 49 | list.push(Shortcuts._code2str(code)); 50 | } 51 | } 52 | return list; 53 | }; 54 | 55 | /** Convert a shortcut string into a code. 56 | * @param {String} shortcut 57 | * @return {Number} 58 | * @private */ 59 | Shortcuts._str2code = function (shortcut) { 60 | 'use strict'; 61 | var checkThat = function (condition, errorStr) { 62 | if (!condition) { throw new Error(errorStr); } 63 | }; 64 | var keys = shortcut.trim().toUpperCase().split(/\s*\+\s*/).filter( 65 | function (str) { return (str.length > 0); } 66 | ); 67 | checkThat(keys.length > 0, 'Empty shortcut string.'); 68 | var code = Shortcuts.KeyCodes[keys.pop()]; 69 | checkThat(code, 'Invalid key name.'); 70 | var flag; 71 | while (keys.length) { 72 | flag = Shortcuts.FlagCodes[keys.pop()]; 73 | checkThat(flag, 'Invalid key combination.'); 74 | code |= flag; 75 | } 76 | return code; 77 | }; 78 | 79 | /** Convert a shortcut code into a string. 80 | * @param {Number} code 81 | * @return {String} 82 | * @private */ 83 | Shortcuts._code2str = function (code) { 84 | 'use strict'; 85 | var array = []; 86 | var flag, name; 87 | for (flag in Shortcuts.FlagNames) { 88 | if (Shortcuts.FlagNames.hasOwnProperty(flag)) { 89 | name = Shortcuts.FlagNames[flag]; 90 | if ((code & flag) && name[0] !== '_') { 91 | array.push(name); 92 | } 93 | } 94 | } 95 | name = Shortcuts.KeyNames[code & Shortcuts.FlagCodes._MASK]; 96 | if (!name) { 97 | throw new Error('Invalid shortcut code.'); 98 | } 99 | array.push(name); 100 | return array.join('+'); 101 | }; 102 | 103 | /** Get the key code from an event. 104 | * @param {KeyboardEvent} evt 105 | * @return {Number} 106 | * @private*/ 107 | Shortcuts._event2code = function (evt) { 108 | 'use strict'; 109 | var key = evt.which || evt.keyCode; 110 | if (evt.altKey) { key |= Shortcuts.FlagCodes.ALT; } 111 | if (evt.ctrlKey) { key |= Shortcuts.FlagCodes.CTRL; } 112 | if (evt.shiftKey) { key |= Shortcuts.FlagCodes.SHIFT; } 113 | return key; 114 | }; 115 | 116 | /** Callback function when a key is pressed on an element with shortcuts. 117 | * @param {KeyboardEvent} evt 118 | * @private */ 119 | Shortcuts._handleEvent = function (evt) { 120 | 'use strict'; 121 | var key = Shortcuts._event2code(evt); 122 | if (this._shortcuts[key]) { 123 | evt.preventDefault(); 124 | evt.stopPropagation(); 125 | this._shortcuts[key].call(this, evt); 126 | return false; 127 | } 128 | }; 129 | 130 | /** Callback function to prevent default action of shortcuts. 131 | * @param {KeyboardEvent} evt 132 | * @private */ 133 | Shortcuts._handleDefaultPrevention = function (evt) { 134 | 'use strict'; 135 | var key = Shortcuts._event2code(evt); 136 | if (this._shortcuts[key]) { 137 | evt.preventDefault(); 138 | evt.stopPropagation(); 139 | return false; 140 | } 141 | }; 142 | 143 | /* Key names (keys = key codes). Documented later, otherwise won't compile. */ 144 | Shortcuts.KeyNames = { 145 | 9: 'Tab', 146 | 8: 'Backspace', 147 | 13: 'Enter', 148 | 27: 'Escape', 149 | 37: 'ArrowLeft', 150 | 38: 'ArrowUp', 151 | 39: 'ArrowRight', 152 | 40: 'ArrowDown', 153 | 33: 'PageUp', 154 | 34: 'PageDown', 155 | 36: 'Home', 156 | 35: 'End', 157 | 45: 'Insert', 158 | 46: 'Delete', 159 | 19: 'Pause', 160 | 161 | // Alphanumeric Keys 162 | 17: 'Ctrl', 163 | 18: 'Alt', 164 | 16: 'Shift', 165 | 65: 'A', 166 | 66: 'B', 167 | 67: 'C', 168 | 68: 'D', 169 | 69: 'E', 170 | 70: 'F', 171 | 71: 'G', 172 | 72: 'H', 173 | 73: 'I', 174 | 74: 'J', 175 | 75: 'K', 176 | 76: 'L', 177 | 77: 'M', 178 | 78: 'N', 179 | 79: 'O', 180 | 80: 'P', 181 | 81: 'Q', 182 | 82: 'R', 183 | 83: 'S', 184 | 84: 'T', 185 | 85: 'U', 186 | 86: 'V', 187 | 87: 'W', 188 | 88: 'X', 189 | 89: 'Y', 190 | 90: 'Z', 191 | 48: '0', 192 | 49: '1', 193 | 50: '2', 194 | 51: '3', 195 | 52: '4', 196 | 53: '5', 197 | 54: '6', 198 | 55: '7', 199 | 56: '8', 200 | 57: '9', 201 | 187: 'Equal', 202 | 203 | // Numpad Keys 204 | 96: 'Num0', 205 | 97: 'Num1', 206 | 98: 'Num2', 207 | 99: 'Num3', 208 | 100: 'Num4', 209 | 101: 'Num5', 210 | 102: 'Num6', 211 | 103: 'Num7', 212 | 104: 'Num8', 213 | 105: 'Num9', 214 | 20: 'CapsLock', 215 | 110: 'Point', 216 | 107: 'Plus', 217 | 109: 'Minus', 218 | 106: 'Times', 219 | 111: 'Divide', 220 | 221 | // Function Keys 222 | 112: 'F1', 223 | 113: 'F2', 224 | 114: 'F3', 225 | 115: 'F4', 226 | 116: 'F5', 227 | 117: 'F6', 228 | 118: 'F7', 229 | 119: 'F8', 230 | 120: 'F9', 231 | 121: 'F10', 232 | 122: 'F11', 233 | 123: 'F12' 234 | }; 235 | 236 | /** Key codes (keys = uppercase key names). @private @type {Object} */ 237 | Shortcuts.KeyCodes = (function () { 238 | 'use strict'; 239 | var code, obj = {}; 240 | for (code in Shortcuts.KeyNames) { 241 | if (Shortcuts.KeyNames.hasOwnProperty(code)) { 242 | obj[Shortcuts.KeyNames[code].toUpperCase()] = code; 243 | } 244 | } 245 | return obj; 246 | }()); 247 | 248 | /** Flag names (keys = flag values). @private @type {Object}. */ 249 | Shortcuts.FlagNames = { 250 | 0x1000: 'Alt', 251 | 0x2000: 'Ctrl', 252 | 0x4000: 'Shift', 253 | 0x0FFF: '_mask' 254 | }; 255 | 256 | /** Flag codes (keys = flag names, e.g. `ALT`). @private @type {Object} */ 257 | Shortcuts.FlagCodes = (function () { 258 | 'use strict'; 259 | var code, obj = {}; 260 | for (code in Shortcuts.FlagNames) { 261 | if (Shortcuts.FlagNames.hasOwnProperty(code)) { 262 | obj[Shortcuts.FlagNames[code].toUpperCase()] = code; 263 | } 264 | } 265 | return obj; 266 | }()); 267 | 268 | // Below is some postponed doc that jsduck won't compile otherwise. 269 | /** Key names (keys = key codes). @readonly @property {Object} KeyNames */ 270 | -------------------------------------------------------------------------------- /examples/colorenhancement/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Color Enhancement in the Wavelet Domain 22 | 23 | 24 | 25 | 26 |
27 | 28 |
29 |
30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 |
39 | Options 40 | 41 | 46 | 47 | 52 | 53 | 54 | 55 | 56 | 60 |
61 |
62 | 63 |
64 | Color enhancement 65 | 66 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 93 | 94 | 110 | 111 |
112 | 113 | 114 |
115 |
116 | 117 |
118 |

How to use this demo

119 |

120 | This demo implements the algorithm introduced in the paper 121 | A Wavelet Perspective on Variational Perceptually-Inspired Color Enhancement 122 | published in 2014 by E Provenzi and V Caselles. 123 | This algorithm performs color and contrast enhancement in the wavelet domain and this demo allows you to test it on your own images. 124 | Note that image larger than 1200x1200 are resized to avoid too long computation time and/or mermory consumption. 125 |

126 |

Instructions

127 |
    128 |
  • 129 | First upload an image using the file selector in the top left part of this page. 130 |
  • 131 |
  • 132 | The in the color enhancement section, you may set your parameters and then click on Apply to see the algorithm effect on the uploaded picture. 133 | The computation may take several seconds. 134 |
  • 135 |
  • 136 | Once the image is processed, it will be displayed and you can use the arrow keys to navigate between the original image, 137 | the processed image or see differences between these images. These different pictures are also available with the View selector. 138 |
  • 139 |
140 | The Stretch dynamic selector allows to expand the image dynamic after algorithm processing. 141 | The stretching can be done either on the luminance channel or oon each RGB channel independently. 142 |

Parameters

143 | The best way to understand then is with any doubt to read the paper, but i provide some hint to build intuition on their effects. 144 |
    145 |
  • 146 | α: For each channel, it controls the dispersion arround the average value. 147 | Set to zero, this parameter has no effect, while set to 1 the image will be washed out. 148 |
  • 149 |
  • 150 | w: It controls the contrast enhancement the bigger the value the greater the effect. 151 |
  • 152 |
  • 153 | K: It controls the magnitude of details enhanced. Small values (1) will only enhance the strongest edges while 154 | greater values will also enhance small details, noise included. 155 |
  • 156 |
  • 157 | γ: This parameter is not described in the article, it implements a gamma functionnal for the φ variable used in the article. 158 |
  • 159 |
  • 160 | Γ: This parameter is also not described in the article, it allows for applying a global gamma correction 161 | on the input image before processing. This gamma correction is reverted after processing on the output data. 162 | Generally values arround 0.5 provide very nice results. 163 |
  • 164 |
165 | 166 |

167 | 168 | 169 |
170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /examples/ppl/ppl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Illuminant Estimation with Projections on Planckian Locus 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 | 38 | 39 | 41 |
42 | 43 |
44 | PPL parameters 45 | 46 | 47 | 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 | 62 |
63 | Options 64 | 65 | 71 | 72 | 94 |
95 | 96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
107 | 108 |
109 |
110 | 111 |
112 |
113 |
114 |
115 |
116 | 117 |
118 |

How to use this demo

119 |

120 | This demo aims at demonstrating the abilities of the PPL (projections on planckian locus) algorithm. 121 | It allows you to upload an image, set a white reference from a white chart in the picture, remove this white chart, 122 | and finally run several algorithms and compare how well they estimate the illuminant. 123 |

124 |

125 | All the algorithms rely linear images, which means that we remove the gamma correction before computing the estimation. 126 | Therefore, the errors are as well are computed on linear images. 127 |

128 |

Instructions

129 |
    130 |
  • 131 | First upload an image using the file selector in the top left part of this page. 132 |
  • 133 |
  • 134 | Select a white reference using shift+dragging to select a rectangular area on the image. 135 | The estimation is done by averaging the pixels selected. A corresponding scatter plot will also appeared in the chromaticity diagram. 136 |
  • 137 |
  • 138 | On the left panel, replace "White patch selection" with "White chart removal" option. Then 139 | using shift+dragging on the image you will be able to remove this white chart to avoid biasing the estimations. 140 |
  • 141 |
  • 142 | Then you can click on launch the benchmark button. Processing may take up to one minute. 143 | Once it finishes, you can choose the correction to apply on the image via the "Correction done with" selector. 144 | A small log will also be displayed, summing up the errors obtained for each algorithm. 145 |
  • 146 |
147 | 148 |

Plots guideline

149 |
    150 |
  • 151 | Navigation in the picture may be done using dragging for translation and mouse wheel for zoom in/out. 152 |
  • 153 |
  • 154 | Click on the image or on the chromaticity diagram will correct the image white balance based either 155 | on the pixel color or the chromaticity selected. 156 |
  • 157 |
  • 158 | Depending on the Image selection field value, shift+dragging on the image diagram will: 159 |
      160 |
    • 161 | Select a white patch reference by averaging the pixels, and plot the chromaticities into the chromaticity diagram. 162 |
    • 163 |
    • 164 | Select and remove part of the picture. 165 |
    • 166 |
    • 167 | Produce a scatter plot of the selected pixels. 168 | Please be careful with large areas selection they can slow down the application significantly.. 169 |
    • 170 |
    171 |
  • 172 |
173 | 174 |

Options

175 | The option field set allows you to choose in which diagram the chromaticities are displayed. as well as the rendering illuminant. 176 | 177 |

Notes

178 | To prevent browser crashes and reduce the time required, the allowed image size has been restricted to stay in the range 1200x1200. 179 | 180 | Note that this demo tested was only Chrome and Firefox web browsers, and might not work with the others. 181 |

182 | The code and parameters used to compute grey-world, grey-edge, shades-of-grey and white-patch results results 183 | from an adaptation of a matlab code by Joost Van-de-Weijer that can be found on his webpage. 184 |

185 |

186 | 187 | 188 |
189 | 190 | 191 | 192 | --------------------------------------------------------------------------------