{"id":19234520,"url":"https://github.com/alemart/speedy-vision","last_synced_at":"2025-04-06T11:08:31.300Z","repository":{"id":40493834,"uuid":"260306364","full_name":"alemart/speedy-vision","owner":"alemart","description":"GPU-accelerated Computer Vision for JavaScript.","archived":false,"fork":false,"pushed_at":"2024-07-03T02:42:49.000Z","size":49179,"stargazers_count":178,"open_issues_count":7,"forks_count":29,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-30T09:05:29.263Z","etag":null,"topics":["computer-vision","gpgpu","gpu","image-processing","linear-algebra","machine-vision","opencv"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alemart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"alemart","patreon":null,"open_collective":null,"ko_fi":"alemart","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-04-30T20:00:13.000Z","updated_at":"2025-03-24T21:32:54.000Z","dependencies_parsed_at":"2023-02-18T17:30:54.445Z","dependency_job_id":"df882ad4-9b38-4afe-ad13-c19b2c559e22","html_url":"https://github.com/alemart/speedy-vision","commit_stats":{"total_commits":1706,"total_committers":6,"mean_commits":284.3333333333333,"dds":0.004103165298944944,"last_synced_commit":"48934ac8317a5b7c3a665af00c69d22e626b888a"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alemart%2Fspeedy-vision","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alemart%2Fspeedy-vision/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alemart%2Fspeedy-vision/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alemart%2Fspeedy-vision/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alemart","download_url":"https://codeload.github.com/alemart/speedy-vision/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247471519,"owners_count":20944158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-vision","gpgpu","gpu","image-processing","linear-algebra","machine-vision","opencv"],"created_at":"2024-11-09T16:14:00.892Z","updated_at":"2025-04-06T11:08:31.274Z","avatar_url":"https://github.com/alemart.png","language":"JavaScript","funding_links":["https://github.com/sponsors/alemart","https://ko-fi.com/alemart","https://ko-fi.com/J3J41O00K"],"categories":[],"sub_categories":[],"readme":"# Speedy Vision\n\n[![GitHub](https://img.shields.io/github/license/alemart/speedy-vision)](LICENSE) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/alemart/speedy-vision)](https://github.com/alemart/speedy-vision/releases) [![GitHub Repo stars](https://img.shields.io/github/stars/alemart/speedy-vision?logo=github)](https://github.com/alemart/speedy-vision/stargazers) [![GitHub Sponsors](https://img.shields.io/github/sponsors/alemart?logo=github)](https://github.com/sponsors/alemart)\n\nBuild real-time stuff with **Speedy Vision**, a GPU-accelerated Computer Vision library for JavaScript.\n\n[\u003cimg src=\"assets/demo-bestfeatures.gif\" alt=\"Speedy feature detection\"\u003e](https://alemart.github.io/speedy-vision/demos/best-features.html \"Click to open a demo\")\n\n**Speedy Vision** is developed independently by [Alexandre Martins](https://github.com/alemart) and released under the [Apache-2.0 license](LICENSE).\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/J3J41O00K)\n\nFor web-based Augmented Reality, [check out my other project](https://github.com/alemart/martins-js).\n\n## Features\n\n* Feature detection\n  * Harris corner detector\n  * FAST feature detector\n  * ORB feature descriptor\n* Feature tracking\n  * KLT feature tracker\n  * LK optical flow\n* Feature matching\n  * Fast approximate k-nearest neighbors (kNN)\n  * Brute force matching\n* Geometric transformations\n  * Homography matrix\n  * Affine transform\n* Image processing\n  * Convert to greyscale\n  * Convolution\n  * Gaussian blur, box \u0026 median filters\n  * Contrast and brightness adjustment\n  * Image normalization \u0026 warping\n  * Image pyramids\n* Linear Algebra\n  * Beautiful matrix algebra with a fluent interface\n  * Efficient computations with WebAssembly\n  * Systems of linear equations\n  * QR decomposition\n\n... and more in development!\n\nThere are plenty of [demos](#demos) available!\n\n-----\n\n## Table of contents\n\n* [Demos](#demos)\n* [Usage](#usage)\n* [Motivation](#motivation)\n* [The Pipeline](#the-pipeline)\n* [API Reference](#api-reference)\n  * [Media routines](#media-routines)\n    * [Loading your media](#loading-your-media)\n    * [Media properties](#media-properties)\n    * [Playing with your media](#playing-with-your-media)\n  * [Pipeline](#pipeline)\n    * [Basic routines](#basic-routines)\n    * [Basic properties](#basic-properties)\n    * [Basic nodes](#basic-nodes)\n  * [Image processing](#image-processing)\n    * [Image basics](#image-basics)\n    * [Image filters](#image-filters)\n    * [General transformations](#general-transformations)\n  * [Keypoints and descriptors](#keypoints-and-descriptors)\n    * [Keypoint types](#keypoint-types)\n    * [Keypoint basics](#keypoint-basics)\n    * [Keypoint detection](#keypoint-detection)\n    * [Keypoint description](#keypoint-description)\n    * [Keypoint tracking (optical-flow)](#keypoint-tracking)\n    * [Keypoint matching](#keypoint-matching)\n  * [Portals](#portals)\n    * [Image Portals](#image-portals)\n    * [Keypoint Portals](#keypoint-portals)\n  * [Linear Algebra](#linear-algebra)\n    * [Creating new matrices](#creating-new-matrices)\n    * [Matrix properties](#matrix-properties)\n    * [Reading from the matrices](#reading-from-the-matrices)\n    * [Writing to the matrices](#writing-to-the-matrices)\n    * [Elementary operations](#elementary-operations)\n    * [Access by block](#access-by-block)\n    * [Functional programming](#functional-programming)\n    * [Systems of equations](#systems-of-equations)\n    * [Matrix factorization](#matrix-factorization)\n  * [Geometric transformations](#geometric-transformations)\n    * [Homography](#perspective-transformation)\n  * [Geometric Utilities](#geometric-utilities)\n    * [2D vectors](#2d-vectors)\n    * [2D points](#2d-points)\n    * [2D size](#2d-size)\n  * [Extras](#extras)\n    * [Promises](#promises)\n    * [Utilities](#utilities)\n    * [Platform](#platform)\n* [Unit tests](https://alemart.github.io/speedy-vision/tests/index.html)\n\n## Demos\n\nTry the demos and take a look at their source code:\n\n* [Hello, world!](https://alemart.github.io/speedy-vision/demos/hello-world.html)\n* Feature detection\n  * [Feature detection in a webcam](https://alemart.github.io/speedy-vision/demos/webcam-demo.html)\n  * [Feature detection in an image](https://alemart.github.io/speedy-vision/demos/image-features.html)\n  * [Feature detection in a video](https://alemart.github.io/speedy-vision/demos/video-features.html)\n  * [Find the best Harris corners](https://alemart.github.io/speedy-vision/demos/best-features.html)\n  * [ORB features](https://alemart.github.io/speedy-vision/demos/orb-features.html)\n* Feature tracking\n  * [Optical flow](https://alemart.github.io/speedy-vision/demos/optical-flow.html)\n* Feature matching\n  * [Feature matching](https://alemart.github.io/speedy-vision/demos/feature-matching.html)\n  * [LSH feature matching](https://alemart.github.io/speedy-vision/demos/feature-matching-lsh.html)\n* Image processing\n  * [Image convolution](https://alemart.github.io/speedy-vision/demos/convolution.html)\n  * [Image warping](https://alemart.github.io/speedy-vision/demos/warping.html)\n  * [Alpha blending](https://alemart.github.io/speedy-vision/demos/alpha-blending.html)\n  * [Resize image](https://alemart.github.io/speedy-vision/demos/resize-image.html)\n  * [Nightvision camera](https://alemart.github.io/speedy-vision/demos/nightvision-camera.html)\n  * [Convert image to greyscale](https://alemart.github.io/speedy-vision/demos/greyscale-image.html)\n  * [Convert video to greyscale](https://alemart.github.io/speedy-vision/demos/greyscale-video.html)\n  * [Blurring an image](https://alemart.github.io/speedy-vision/demos/image-blurring.html)\n  * [Blurring a video with a median filter](https://alemart.github.io/speedy-vision/demos/median-filter.html)\n  * [Normalize camera stream](https://alemart.github.io/speedy-vision/demos/normalize-demo.html)\n  * [Image Portals](https://alemart.github.io/speedy-vision/demos/image-portal.html)\n* Linear Algebra\n  * [System of equations](https://alemart.github.io/speedy-vision/demos/system-of-equations.html)\n  * [QR decomposition](https://alemart.github.io/speedy-vision/demos/qr-decomposition.html)\n\n## Usage\n\n### Browser\n\n[Download the latest release of Speedy Vision](https://github.com/alemart/speedy-vision/releases) and include it in the `\u003chead\u003e` section of your HTML page:\n\n```html\n\u003cscript src=\"dist/speedy-vision.min.js\"\u003e\u003c/script\u003e\n```\n\nOnce you import the library, the `Speedy` object will be exposed. Check out the [Hello World demo](https://alemart.github.io/speedy-vision/demos/hello-world.html) for a working example.\n\n### Via CDN\n\nAdd the following to the `\u003chead\u003e` of your HTML page:\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alemart/speedy-vision@VERSION/dist/speedy-vision.min.js\"\u003e\u003c/script\u003e\n```\n\nReplace `VERSION` by ![GitHub release (latest by date)](https://img.shields.io/github/v/release/alemart/speedy-vision?color=%23ffffff\u0026display_name=tag\u0026label=%20)\n\n### Via npm\n\nSimply run:\n\n```sh\nnpm install speedy-vision\n```\n\nNext, import the `Speedy` object as follows:\n\n```js\nimport Speedy from 'speedy-vision';\n```\n\n## Motivation\n\nDetecting features in an image is an important step of many computer vision algorithms. Traditionally, the computationally expensive nature of this process made it difficult to bring interactive Computer Vision applications to the web browser. The framerates were unsatisfactory for a compelling user experience. Speedy, a short name for Speedy Vision, is a JavaScript library created to address this issue.\n\nSpeedy's real-time performance in the web browser is possible thanks to its efficient WebGL2 backend and to its GPU implementations of fast computer vision algorithms. With an easy-to-use API, Speedy is an excellent choice for real-time computer vision projects involving tasks such as: object detection in videos, pose estimation, Simultaneous Location and Mapping (SLAM), and others.\n\n## The Pipeline\n\nThe pipeline is a central concept in Speedy. It's a powerful structure that lets you organize the computations that take place in the GPU. It's a very flexible, yet conceptually simple, way of working with computer vision and image processing. Let's define a few things:\n\n- A **pipeline** is a network of **nodes** in which data flows downstream from one or more sources to one or more sinks.\n- Nodes have input and/or output **ports**. A node with no input ports is called a **source**. A node with no output ports is called a **sink**. A node with both input and output ports transforms the input data in some way and writes the results to its output port(s).\n- A **link** connects an output port of a node to an input port of another node. Two nodes are said to be connected if there is a link connecting their ports. Data flows from one node to another by means of a link. An input port may only be connected to a single output port, but an output port may be connected to multiple input ports.\n- Input ports expect data of a certain **type** (e.g., an image). Output ports hold data of a certain type. Two ports may only be connected if their types match.\n- Ports may impose additional **constraints** on the data passing through them. For example, an input port may expect an image and also impose the constraint that this image must be greyscale.\n- Different nodes may have different **parameters**. These parameters can be adjusted and are meant to modify the output of the nodes in some way.\n- Nodes and their ports have **names**. An input port is typically called `\"in\"`. An output port is typically called `\"out\"`. These names can vary, e.g., if a node has more than one input / output port. Speedy automatically assigns names to the nodes, but you can assign your own names as well.\n\nThe picture below shows a visual representation of a pipeline that converts an image or video to greyscale. Data gets into the pipeline via the image source. It is then passed to the Convert to greyscale node. Finally, a greyscale image goes into the image sink, where it gets out of the pipeline.\n\n![Convert to greyscale: a simple pipeline](assets/network-example.png)\n\nHere's a little bit of code:\n\n```js\n// Load an image\nconst img = document.querySelector('img');\nconst media = await Speedy.load(img);\n\n// Create the pipeline and the nodes\nconst pipeline = Speedy.Pipeline();\nconst source = Speedy.Image.Source();\nconst sink = Speedy.Image.Sink();\nconst greyscale = Speedy.Filter.Greyscale();\n\n// Set the media source\nsource.media = media; // media is a SpeedyMedia object\n\n// Connect the nodes\nsource.output().connectTo(greyscale.input());\ngreyscale.output().connectTo(sink.input());\n\n// Specify the nodes to initialize the pipeline\npipeline.init(source, sink, greyscale);\n\n// Run the pipeline\nconst { image } = await pipeline.run(); // image is a SpeedyMedia\n\n// Create a \u003ccanvas\u003e to display the result\nconst canvas = document.createElement('canvas');\ncanvas.width = image.width;\ncanvas.height = image.height;\ndocument.body.appendChild(canvas);\n\n// Display the result\nconst ctx = canvas.getContext('2d');\nctx.drawImage(media.source, 0, 0);\n```\n\nSpeedy provides many types of nodes. You can connect these nodes in a way that is suitable to your application, and Speedy will bring back the results you ask for.\n\n## API Reference\n\n### Media routines\n\nA `SpeedyMedia` object encapsulates a media object: an image, a video, a canvas or a bitmap.\n\n#### Loading your media\n\n##### Speedy.load()\n\n`Speedy.load(source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap, options?: object): SpeedyPromise\u003cSpeedyMedia\u003e`\n\nTells Speedy to load `source`. The `source` parameter may be an image, a video, a canvas or a bitmap.\n\n###### Arguments\n\n* `source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap`. The media source.\n* `options: object, optional`. Additional options for advanced configuration. See [SpeedyMedia.options](#speedymediaoptions) for details.\n\n###### Returns\n\nA `SpeedyPromise\u003cSpeedyMedia\u003e` that resolves as soon as the media source is loaded.\n\n###### Example\n\n```js\nwindow.onload = async function() {\n    let image = document.getElementById('my-image'); // \u003cimg id=\"my-image\" src=\"...\"\u003e\n    let media = await Speedy.load(image);\n}\n```\n\n##### Speedy.camera()\n\n`Speedy.camera(width?: number, height?: number): SpeedyPromise\u003cSpeedyMedia\u003e`\n\n`Speedy.camera(constraints: MediaStreamConstraints): SpeedyPromise\u003cSpeedyMedia\u003e`\n\nLoads a camera stream into a new `SpeedyMedia` object. This is a wrapper around `navigator.mediaDevices.getUserMedia()`, provided for your convenience.\n\n###### Arguments\n\n* `width: number, optional`. The ideal width of the stream. The browser will use this value or a close match. Defaults to `640`.\n* `height: number, optional`. The ideal height of the stream. The browser will use this value or a close match. Defaults to `360`.\n* `constraints: MediaStreamConstraints`. A [MediaStreamConstraints](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints) dictionary to be passed to `getUserMedia()` for complete customization.\n\n###### Returns\n\nA `SpeedyPromise\u003cSpeedyMedia\u003e` that resolves as soon as the media source is loaded with the camera stream.\n\n###### Example\n\n```js\n// Display the contents of a webcam\nwindow.onload = async function() {\n    const media = await Speedy.camera();\n    const canvas = createCanvas(media.width, media.height);\n    const ctx = canvas.getContext('2d');\n\n    function render()\n    {\n        ctx.drawImage(media.source, 0, 0);\n        requestAnimationFrame(render);\n    }\n\n    render();\n}\n\nfunction createCanvas(width, height)\n{\n    const canvas = document.createElement('canvas');\n\n    canvas.width = width;\n    canvas.height = height;\n    document.body.appendChild(canvas);\n\n    return canvas;\n}\n```\n\n##### SpeedyMedia.release()\n\n`SpeedyMedia.release(): null`\n\nReleases internal resources associated with this `SpeedyMedia`.\n\n###### Returns\n\nReturns `null`.\n\n#### Media properties\n\n##### SpeedyMedia.source\n\n`SpeedyMedia.source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | ImageData, read-only`\n\nThe media source associated with the `SpeedyMedia` object.\n\n##### SpeedyMedia.type\n\n`SpeedyMedia.type: string, read-only`\n\nThe type of the media source. One of the following: `\"image\"`, `\"video\"`, `\"canvas\"`, `\"offscreen-canvas\"`, `\"bitmap\"`, `\"data\"`.\n\nSee also: [SpeedyMedia.source](#speedymediasource).\n\n##### SpeedyMedia.width\n\n`SpeedyMedia.width: number, read-only`\n\nThe width of the media source, in pixels.\n\n##### SpeedyMedia.height\n\n`SpeedyMedia.height: number, read-only`\n\nThe height of the media source, in pixels.\n\n##### SpeedyMedia.size\n\n`SpeedyMedia.size: SpeedySize, read-only`\n\nThe size of the media, in pixels.\n\n##### SpeedyMedia.options\n\n`SpeedyMedia.options: object, read-only`\n\nRead-only object defined when [loading the media](#speedyload). Deprecated.\n\n#### Playing with your media\n\n##### SpeedyMedia.clone()\n\n`SpeedyMedia.clone(): SpeedyPromise\u003cSpeedyMedia\u003e`\n\nClones the `SpeedyMedia` object.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to a clone of the `SpeedyMedia` object.\n\n###### Example\n\n```js\nconst clone = await media.clone();\n```\n\n##### SpeedyMedia.toBitmap()\n\n`SpeedyMedia.toBitmap(): SpeedyPromise\u003cImageBitmap\u003e`\n\nConverts the media to an `ImageBitmap`.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to an `ImageBitmap`.\n\n### Pipeline\n\n#### Basic routines\n\n##### Speedy.Pipeline.Pipeline()\n\n`Speedy.Pipeline.Pipeline(): SpeedyPipeline`\n\nCreates a new, empty pipeline.\n\n###### Returns\n\nA new `SpeedyPipeline` object.\n\n##### SpeedyPipeline.init()\n\n`SpeedyPipeline.init(...nodes: SpeedyPipelineNode[]): SpeedyPipeline`\n\nInitializes a pipeline with the specified `nodes`.\n\n###### Arguments\n\n* `...nodes: SpeedyPipelineNode[]`. The list of nodes that belong to the pipeline.\n\n###### Returns\n\nThe pipeline itself.\n\n###### Example\n\n```js\nconst pipeline = Speedy.Pipeline(); // create the pipeline and the nodes\nconst source = Speedy.Image.Source();\nconst sink = Speedy.Image.Sink();\nconst greyscale = Speedy.Filter.Greyscale();\n\nsource.media = media; // set the media source\n\nsource.output().connectTo(greyscale.input()); // connect the nodes\ngreyscale.output().connectTo(sink.input());\n\npipeline.init(source, sink, greyscale); // add the nodes to the pipeline\n```\n\n##### SpeedyPipeline.release()\n\n`SpeedyPipeline.release(): null`\n\nReleases the resources associated with `this` pipeline.\n\n###### Returns\n\nReturns `null`.\n\n##### SpeedyPipeline.run()\n\n`SpeedyPipeline.run(): SpeedyPromise\u003cobject\u003e`\n\nRuns `this` pipeline.\n\n###### Returns\n\nReturns a `SpeedyPromise` that resolves to an object whose keys are the names of the sinks of the pipeline and whose values are the data exported by those sinks.\n\n###### Example\n\n```js\nconst { sink1, sink2 } = await pipeline.run();\n```\n\n##### SpeedyPipeline.node()\n\n`SpeedyPipeline.node(name: string): SpeedyPipelineNode | null`\n\nFinds a node by its `name`.\n\n###### Arguments\n\n* `name: string`. Name of the target node.\n\n###### Returns\n\nReturns a `SpeedyPipelineNode` that has the specified `name` and that belongs to `this` pipeline, or `null` if there is no such node.\n\n##### SpeedyPipelineNode.input()\n\n`SpeedyPipelineNode.input(portName?: string): SpeedyPipelineNodePort`\n\nThe input port of `this` node whose name is `portName`.\n\n###### Arguments\n\n* `portName: string, optional`. The name of the port you want to access. Defaults to `\"in\"`.\n\n###### Returns\n\nThe requested input port.\n\n##### SpeedyPipelineNode.output()\n\n`SpeedyPipelineNode.output(portName?: string): SpeedyPipelineNodePort`\n\nThe output port of `this` node whose name is `portName`.\n\n###### Arguments\n\n* `portName: string, optional`. The name of the port you want to access. Defaults to `\"out\"`.\n\n###### Returns\n\nThe requested output port.\n\n##### SpeedyPipelineNodePort.connectTo()\n\n`SpeedyPipelineNodePort.connectTo(port: SpeedyPipelineNodePort): void`\n\nCreates a link connecting `this` port to another `port`.\n\n#### Basic properties\n\n##### SpeedyPipelineNode.name\n\n`SpeedyPipelineNode.name: string, read-only`\n\nThe name of the node.\n\n##### SpeedyPipelineNode.fullName\n\n`SpeedyPipelineNode.fullName: string, read-only`\n\nA string that exhibits the name and the type of the node.\n\n##### SpeedyPipelineNodePort.name\n\n`SpeedyPipelineNodePort.name: string, read-only`\n\nThe name of the port.\n\n##### SpeedyPipelineNodePort.node\n\n`SpeedyPipelineNodePort.node: SpeedyPipelineNode, read-only`\n\nThe node to which `this` port belongs.\n\n#### Basic nodes\n\n##### Speedy.Image.Source()\n\n`Speedy.Image.Source(name?: string): SpeedyPipelineNodeImageInput`\n\nCreates an image source with the specified name. If the name is not specified, Speedy will automatically generate a name for you.\n\n###### Parameters\n\n* `media: SpeedyMedia`. The media to be imported into the pipeline.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"out\"`   | Image     | An image corresponding to the `media` of this node. |\n\n##### Speedy.Image.Sink()\n\n`Speedy.Image.Sink(name?: string): SpeedyPipelineNodeImageOutput`\n\nCreates an image sink with the specified name. If the name is not specified, Speedy will call this node `\"image\"`. A `SpeedyMedia` object will be exported from the pipeline.\n\n###### Parameters\n\n* `mediaType: \"bitmap\" | \"data\"`. The desired [type](#speedymediatype) of the [source](#speedymediasource) of the exported `SpeedyMedia`. Use `\"bitmap\"` to be able to draw the exported image to a canvas without undue latency, or `\"data\"` to be able to access its pixel data directly. Defaults to `\"bitmap\"`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | An image to be exported from the pipeline. |\n\n### Image processing\n\n#### Image basics\n\n##### Speedy.Image.Pyramid()\n\n`Speedy.Image.Pyramid(name?: string): SpeedyPipelineNodeImagePyramid`\n\nGenerate a Gaussian pyramid. A pyramid is a texture with mipmaps.\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | Gaussian pyramid. |\n\n##### Speedy.Image.Multiplexer()\n\n`Speedy.Image.Multiplexer(name?: string): SpeedyPipelineNodeImageMultiplexer`\n\nAn image multiplexer receives two images as input and outputs one of the them.\n\n###### Parameters\n\n* `port: number`. Which input image should be redirected to the output: `0` or `1`? Defaults to `0`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in0\"`   | Image     | First image. |\n| `\"in1\"`   | Image     | Second image. |\n| `\"out\"`   | Image     | Either the first or the second image, depending on the value of `port`. |\n\n##### Speedy.Image.Buffer()\n\n`Speedy.Image.Buffer(name?: string): SpeedyPipelineNodeImageBuffer`\n\nAn image buffer outputs at time *t* the input image received at time *t-1*. It's useful for tracking.\n\n**Note:** an image buffer cannot be used to store a pyramid at this time.\n\n###### Parameters\n\n* `frozen: boolean`. A frozen buffer discards the input, effectively increasing the buffering time. Defaults to `false`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image at time *t*. |\n| `\"out\"`   | Image     | Output image: the input image at time *t-1*. |\n\n##### Speedy.Image.Mixer()\n\n`Speedy.Image.Mixer(name?: string): SpeedyPipelineNodeImageMixer`\n\nAn image mixer combines two images, *image0* and *image1*, as follows:\n\n*output* = `alpha` * *image0* + `beta` * *image1* + `gamma`\n\nThe above expression will be computed for each pixel of the resulting image and then clamped to the [0,1] interval. The dimensions of the resulting image will be the dimensions of the larger of the input images.\n\n**Note:** Both input images must have the same format. If they're colored, the above expression will be evaluated in each color channel independently.\n\n**Tip:** if you pick an `alpha` between 0 and 1, set `beta` to `1 - alpha` and set `gamma` to 0, you'll get a nice alpha blending effect.\n\n###### Parameters\n\n* `alpha: number`. A scalar value. Defaults to 0.5.\n* `beta: number`. A scalar value. Defaults to 0.5.\n* `gamma: number`. A scalar value. Defaults to 0.0.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in0\"`   | Image     | Input image: the *image0* above |\n| `\"in1\"`   | Image     | Input image: the *image1* above |\n| `\"out\"`   | Image     | Output image |\n\n#### Image filters\n\n##### Speedy.Filter.Greyscale()\n\n`Speedy.Filter.Greyscale(name?: string): SpeedyPipelineNodeGreyscale`\n\nConvert an image to greyscale.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | The input image converted to greyscale. |\n\n##### Speedy.Filter.SimpleBlur()\n\n`Speedy.Filter.SimpleBlur(name?: string): SpeedyPipelineNodeSimpleBlur`\n\nBlur an image using a box filter.\n\n###### Parameters\n\n* `kernelSize: SpeedySize`. The size of the convolution kernel: from 3x3 to 15x15. Defaults to 5x5.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | The input image, blurred. |\n\n##### Speedy.Filter.GaussianBlur()\n\n`Speedy.Filter.SimpleBlur(name?: string): SpeedyPipelineNodeGaussianBlur`\n\nBlur an image using a Gaussian filter.\n\n###### Parameters\n\n* `kernelSize: SpeedySize`. The size of the convolution kernel: from 3x3 to 15x15. Defaults to 5x5.\n* `sigma: SpeedyVector2`. The sigma of the Gaussian function in both x and y axes. If set to the zero vector, Speedy will automatically pick a sigma according to the selected `kernelSize`. Defaults to (0,0).\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | The input image, blurred. |\n\n##### Speedy.Filter.MedianBlur()\n\n`Speedy.Filter.MedianBlur(name?: string): SpeedyPipelineNodeMedianBlur`\n\nMedian filter.\n\n###### Parameters\n\n* `kernelSize: SpeedySize`. One of the following: 3x3, 5x5 or 7x7. Defaults to 5x5.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | A greyscale image. |\n| `\"out\"`   | Image     | The result of the median blur. |\n\n###### Example\n\n```js\nconst median = Speedy.Filter.MedianBlur();\nmedian.kernelSize = Speedy.Size(7,7);\n```\n\n##### Speedy.Filter.Convolution()\n\n`Speedy.Filter.Convolution(name?: string): SpeedyPipelineNodeConvolution`\n\nCompute the convolution of an image using a 2D kernel.\n\n###### Parameters\n\n* `kernel: SpeedyMatrixExpr`. A 3x3, 5x5 or 7x7 matrix.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | The result of the convolution. |\n\n###### Example\n\n```js\n// Sharpening an image\nconst sharpen = Speedy.Filter.Convolution();\nsharpen.kernel = Speedy.Matrix(3, 3, [\n    0,-1, 0,\n   -1, 5,-1,\n    0,-1, 0\n]);\n```\n\n##### Speedy.Filter.Normalize()\n\n`Speedy.Filter.Normalize(name?: string): SpeedyPipelineNodeNormalize`\n\nNormalize the intensity values of the input image to the [`minValue`, `maxValue`] interval.\n\n###### Parameters\n\n* `minValue: number`. A value in [0,255].\n* `maxValue: number`. A value in [0,255] greater than or equal to `minValue`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Greyscale image. |\n| `\"out\"`   | Image     | Normalized image. |\n\n##### Speedy.Filter.Nightvision()\n\n`Speedy.Filter.Nightvision(name?: string): SpeedyPipelineNodeNightvision`\n\nNightvision filter for local contrast stretching and brightness control.\n\n###### Parameters\n\n* `gain: number`. A value in [0,1]: the larger the number, the higher the contrast. Defaults to `0.5`.\n* `offset: number`. A value in [0,1] that controls the brightness. Defaults to `0.5`.\n* `decay: number`. A value in [0,1] specifying a contrast decay from the center of the image. Defaults to zero (no decay).\n* `quality: string`. Quality level: `\"high\"`, `\"medium\"` or `\"low\"`. Defaults to `\"medium\"`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | Output image. |\n\n#### General transformations\n\n##### Speedy.Transform.Resize()\n\n`Speedy.Transform.Resize(name?: string): SpeedyPipelineNodeResize`\n\nResize an image.\n\n###### Parameters\n\n* `size: SpeedySize`. The size of the output image, in pixels. If set to zero, `scale` will be used to determine the size of the output. Defaults to zero.\n* `scale: SpeedyVector2`. The size of the output image relative to the size of the input image. This parameter is only applied if `size` is zero. Defaults to (1,1), meaning: keep the original size.\n* `method: string`. Resize method. One of the following: `\"bilinear\"` (bilinear interpolation) or `\"nearest\"` (nearest neighbors). Defaults to `\"bilinear\"`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | Resized image. |\n\n##### Speedy.Transform.PerspectiveWarp()\n\n`Speedy.Transform.PerspectiveWarp(name?: string): SpeedyPipelineNodePerspectiveWarp`\n\nWarp an image using a [homography matrix](#perspective-transformation).\n\n###### Parameters\n\n* `transform: SpeedyMatrixExpr`. A 3x3 perspective transformation. Defaults to the identity matrix.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Input image. |\n| `\"out\"`   | Image     | Warped image. |\n\n### Keypoints and descriptors\n\nA **keypoint** is a small patch in an image that is somehow *distinctive*. For example, a small patch with significant intensity changes in both x and y axes (i.e., a \"corner\") is distinctive. If we pick two \"similar\" images, we should be able to locate a set of keypoints in each of them and then match those keypoints based on their similarity.\n\nA **descriptor** is a mathematical object that somehow describes a keypoint. Two keypoints are considered to be \"similar\" if their descriptors are \"similar\". Speedy works with binary descriptors, meaning that keypoints are described using bit vectors of fixed length.\n\nThere are different ways to detect and describe keypoints. For example, in order to detect a keypoint, you may take a look at the pixel intensities around a point or perhaps study the image derivatives. You may describe a keypoint by comparing the pixel intensities of the image patch in a special way. Additionally, it's possible to conceive a way to describe a keypoint in such a way that, if you rotate the patch, the descriptor stays roughly the same. This is called *rotational invariance* and is usually a desirable property for a descriptor.\n\nSpeedy offers different options for processing keypoints in multiple ways. A novelty of this work is that Speedy's implementations have been either adapted from the literature or conceived from scratch to work on the GPU. Therefore, keypoint processing is done in parallel and is often very fast.\n\n#### Keypoint types\n\n##### SpeedyKeypoint\n\nA `SpeedyKeypoint` object represents a keypoint.\n\n###### SpeedyKeypoint.position\n\n`SpeedyKeypoint.position: SpeedyPoint2`\n\nThe position of the keypoint in the image.\n\n###### SpeedyKeypoint.x\n\n`SpeedyKeypoint.x: number`\n\nThe x position of the keypoint in the image. A shortcut to `position.x`.\n\n###### SpeedyKeypoint.y\n\n`SpeedyKeypoint.y: number`\n\nThe y position of the keypoint in the image. A shortcut to `position.y`.\n\n###### SpeedyKeypoint.lod\n\n`SpeedyKeypoint.lod: number, read-only`\n\nThe level-of-detail (pyramid level) from which the keypoint was extracted, starting from zero. Defaults to `0.0`.\n\n###### SpeedyKeypoint.scale\n\n`SpeedyKeypoint.scale: number, read-only`\n\nThe scale of the keypoint. This is equivalent to *2 ^ lod*. Defaults to `1.0`.\n\n###### SpeedyKeypoint.rotation\n\n`SpeedyKeypoint.rotation: number, read-only`\n\nThe rotation angle / orientation of the keypoint, in radians. Defaults to `0.0`.\n\n###### SpeedyKeypoint.score\n\n`SpeedyKeypoint.score: number, read-only`\n\nThe score is a measure associated with the keypoint. Although different detection methods employ different measurement strategies, the larger the score, the \"better\" the keypoint is considered to be. The score is always a positive value.\n\n###### SpeedyKeypoint.descriptor\n\n`SpeedyKeypoint.descriptor: SpeedyKeypointDescriptor | null, read-only`\n\nThe descriptor associated with the keypoint, if it exists.\n\n##### SpeedyKeypointDescriptor\n\nA `SpeedyKeypointDescriptor` represents a keypoint descriptor.\n\n###### SpeedyKeypointDescriptor.data\n\n`SpeedyKeypointDescriptor.data: Uint8Array, read-only`\n\nThe bytes of the keypoint descriptor.\n\n###### SpeedyKeypointDescriptor.size\n\n`SpeedyKeypointDescriptor.size: number, read-only`\n\nThe size of the keypoint descriptor, in bytes.\n\n###### SpeedyKeypointDescriptor.toString()\n\n`SpeedyKeypointDescriptor.toString(): string`\n\nReturns a string representation of the keypoint descriptor.\n\n##### SpeedyTrackedKeypoint\n\nA `SpeedyTrackedKeypoint` is a `SpeedyKeypoint` with the following additional properties:\n\n###### SpeedyTrackerKeypoint.flow\n\n`SpeedyTrackedKeypoint.flow: SpeedyVector2, read-only`\n\nA displacement vector associated with the tracked keypoint.\n\n##### SpeedyMatchedKeypoint\n\nA `SpeedyMatchedKeypoint` is a `SpeedyKeypoint` with the following additional properties:\n\n###### SpeedyMatchedKeypoint.matches\n\n`SpeedyMatchedKeypoint.matches: SpeedyKeypointMatch[], read-only`\n\nA list of keypoint matches associated with the keypoint. They will be sorted by increasing distance (better matches come first).\n\nSee also: [SpeedyKeypointMatch](#SpeedyKeypointMatch).\n\n##### SpeedyKeypointMatch\n\nA `SpeedyKeypointMatch` represents a keypoint match.\n\n###### SpeedyKeypointMatch.index\n\n`SpeedyKeypointMatch.index: number, read-only`\n\nThe non-negative index of the matched keypoint in a database of keypoints, or `-1` if there is no match.\n\n###### SpeedyKeypointMatch.distance\n\n`SpeedyKeypointMatch.distance: number, read-only`\n\nA distance metric between the keypoint and the matched keypoint. The lower the distance, the better the match. If there is no match, then this field will be set to infinity.\n\n\n#### Keypoint basics\n\n##### Speedy.Keypoint.Source()\n\n`Speedy.Keypoint.Source(name?: string): SpeedyPipelineNodeKeypointSource`\n\nCreates a source of keypoints. Only the position, score and scale of the provided keypoints will be imported to the pipeline. Descriptors, if present, will be lost.\n\n###### Parameters\n\n* `keypoints: SpeedyKeypoint[]`. The keypoints you want to import.\n* `capacity: number`. The maximum number of keypoints that can be imported to the GPU. If you have an idea of how many keypoints you expect (at most), use a tight bound to make processing more efficient. The default capacity is `2048`. It can be no larger than `8192`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"out\"`   | Keypoints | The imported set of keypoints. |\n\n##### Speedy.Keypoint.Sink()\n\n`Speedy.Keypoint.Sink(name?: string): SpeedyPipelineNodeKeypointSink`\n\nCreates a sink of keypoints using the specified name. If the name is not specified, Speedy will call this node `\"keypoints\"`. An array of `SpeedyKeypoint` objects will be exported from the pipeline.\n\n###### Parameters\n\n* `turbo: boolean`. Accelerate GPU-CPU transfers. You'll get the data from the previous frame. Defaults to `false`.\n* `includeDiscarded: boolean`. Set discarded keypoints (e.g., by a tracker) to `null` in the exported set. Defaults to `false`, meaning that discarded keypoints will simply be dropped from the exported set rather than being set to `null`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints to be exported from the pipeline. |\n\n##### Speedy.Keypoint.Clipper()\n\n`Speedy.Keypoint.Clipper(name?: string): SpeedyPipelineNodeKeypointClipper`\n\nClips a set of keypoints, so that it outputs no more than a fixed quantity of them. When generating the output, it will choose the \"best\" keypoints according to their score metric. The keypoint clipper is a very useful tool to reduce processing time, since it can discard \"bad\" keypoints regardless of the sensitivity of their detector. The clipping must be applied before computing any descriptors.\n\n###### Parameters\n\n* `size: number`. A positive integer. No more than this number of keypoints will be available in the output.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints. |\n| `\"out\"`   | Keypoints | A set of at most `size` keypoints. |\n\n##### Speedy.Keypoint.BorderClipper()\n\n`Speedy.Keypoint.BorderClipper(name?: string): SpeedyPipelineNodeKeypointBorderClipper`\n\nRemoves all keypoints within a specified border of the edge of an image. The border is specified in pixels as an ordered pair of integers: the first is the size of the horizontal border and the second is the size of the vertical border.\n\n###### Parameters\n\n* `imageSize: SpeedySize`. Image size, in pixels.\n* `borderSize: SpeedyVector2`. Border size in both x and y axes. Defaults to zero, meaning that no clipping takes place.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints. |\n| `\"out\"`   | Keypoints | The clipped set of keypoints. |\n\n##### Speedy.Keypoint.Mixer()\n\n`Speedy.Keypoint.Mixer(name?: string): SpeedyPipelineNodeKeypointMixer`\n\nMixes (merges) two sets of keypoints.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in0\"`   | Keypoints | A set of keypoints. |\n| `\"in1\"`   | Keypoints | Another set of keypoints. |\n| `\"out\"`   | Keypoints | The union of the two input sets. |\n\n##### Speedy.Keypoint.Buffer()\n\n`Speedy.Keypoint.Buffer(name?: string): SpeedyPipelineNodeKeypointBuffer`\n\nA keypoint buffer outputs at time *t* the keypoints received at time *t-1*.\n\n###### Parameters\n\n* `frozen: boolean`. A frozen buffer discards the input, effectively increasing the buffering time. Defaults to `false`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints at time *t*. |\n| `\"out\"`   | Keypoints | The set of keypoints received at time *t-1*. |\n\n##### Speedy.Keypoint.Multiplexer()\n\n`Speedy.Keypoint.Multiplexer(name?: string): SpeedyPipelineNodeKeypointMultiplexer`\n\nA keypoint multiplexer receives two sets of keypoints as input and outputs one of the them.\n\n###### Parameters\n\n* `port: number`. Which input set of keypoints should be redirected to the output: `0` or `1`? Defaults to `0`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in0\"`   | Image     | First set of keypoints. |\n| `\"in1\"`   | Image     | Second set of keypoints. |\n| `\"out\"`   | Image     | Either the first or the second set of keypoints, depending on the value of `port`. |\n\n##### Speedy.Keypoint.Transformer()\n\n`Speedy.Keypoint.Transformer(name?: string): SpeedyPipelineNodeKeypointTransformer`\n\nApplies a transformation matrix to a set of keypoints.\n\n###### Parameters\n\n* `transform: SpeedyMatrix`. A 3x3 homography matrix. Defaults to the identity matrix.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints. |\n| `\"out\"`   | Keypoints | A transformed set of keypoints. |\n\n##### Speedy.Keypoint.SubpixelRefiner()\n\n`Speedy.Keypoint.SubpixelRefiner(name?: string): SpeedyPipelineNodeKeypointSubpixelRefiner`\n\nRefines the position of a set of keypoints down to the subpixel level.\n\n**Note 1:** filter the image to reduce the noise before working at the subpixel level.\n\n**Note 2:** if there are keypoints in multiple scales, make sure to provide a pyramid as input.\n\n**Note 3:** the position of the keypoints is stored as fixed-point. This representation may introduce a loss of accuracy (~0.1 pixel). This is probably enough already, but if you need higher accuracy, ignore the output keypoints and work with the displacement vectors instead. These are encoded as floating-point. In addition, use the upsampling methods.\n\n###### Parameters\n\n* `method: string`. The method to be used to compute the subpixel displacement. See the table below.\n* `maxIterations: number`. The maximum number of iterations used by methods `\"bicubic-upsample\"` and `\"bilinear-upsample\"`. Defaults to 6.\n* `epsilon: number`. The threshold used to determine when the subpixel displacement has reached convergence. Used with methods `\"bicubic-upsample\"` and `\"bilinear-upsample\"`. Defaults to 0.1 pixel.\n\nTable of methods:\n\n| Method            | Description |\n|-------------------|-------------|\n| `\"quadratic1d\"` | Maximize a 1D parabola fit to a corner strength function. This is the default method. |\n| `\"taylor2d\"` | Maximize a second-order 2D Taylor expansion of a corner strength function. Method `\"quadratic1d\"` seems to perform slightly better than this, but your mileage may vary.\n| `\"bicubic-upsample\"` | Iteratively upsample the image using bicubic interpolation in order to maximize a corner strength function. Repeat until convergence or until a maximum number of iterations is reached. |\n| `\"bilinear-upsample\"` | Analogous to bicubic upsample, but this method uses bilinear interpolation instead. |\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"image\"` | Image     | An image or pyramid from which you extracted the keypoints. |\n| `\"keypoints\"` | Keypoints | Input set of keypoints. |\n| `\"out\"`   | Keypoints | Subpixel-refined output set of keypoints. |\n| `\"displacements\"` | Vector2 | Displacement vectors (output). |\n\n##### Speedy.Keypoint.DistanceFilter()\n\n`Speedy.Keypoint.DistanceFilter(name?: string): SpeedyPipelineNodeKeypointDistanceFilter`\n\nGiven a set of pairs of keypoints, discard all pairs whose distance is above a user-defined threshold. This is useful for implementing bidirectional optical-flow.\n\nThe pairs of keypoints are provided as two separate sets, \"in\" and \"reference\". Keypoints that are kept will have their data extracted from the \"in\" set.\n\n###### Parameters\n\n* `threshold: number`. Distance threshold, given in pixels.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"` | Keypoints | A set of keypoints. |\n| `\"reference\"` | Keypoints | A reference set of keypoints. |\n| `\"out\"` | Keypoints | Filtered set of keypoints. |\n\n##### Speedy.Keypoint.HammingDistanceFilter()\n\n`Speedy.Keypoint.HammingDistanceFilter(name?: string): SpeedyPipelineNodeKeypointHammingDistanceFilter`\n\nGiven a set of pairs of keypoints with descriptors, discard all pairs whose Hamming distance between their descriptors is above a user-defined threshold.\n\nThe pairs of keypoints are provided as two separate sets, \"in\" and \"reference\". Keypoints that are kept will have their data extracted from the \"in\" set.\n\n###### Parameters\n\n* `threshold: number`. Distance threshold, an integer.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"` | Keypoints | A set of keypoints. |\n| `\"reference\"` | Keypoints | A reference set of keypoints. |\n| `\"out\"` | Keypoints | Filtered set of keypoints. |\n\n##### Speedy.Keypoint.Shuffler()\n\n`Speedy.Keypoint.Shuffler(name?: string): SpeedyPipelineNodeKeypointShuffler`\n\nShuffles the input keypoints, optionally clipping the output set.\n\n###### Parameters\n\n* `maxKeypoints: number`. Maximum number of keypoints of the output set. If unspecified, the number of keypoints of the output set will be the number of keypoints of the input set.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints. |\n| `\"out\"`   | Keypoints | The input set of keypoints, shuffled and possibly clipped. |\n\n\n\n\n#### Keypoint detection\n\nThe following nodes expect greyscale images as input. They output a set of keypoints.\n\n##### Speedy.Keypoint.Detector.FAST()\n\n`Speedy.Keypoint.Detector.FAST(name?: string): SpeedyPipelineNodeFASTKeypointDetector`\n\nFAST keypoint detector. Speedy implements the FAST-9,16 variant of the algorithm.\n\nTo use the multi-scale version of the algorithm, pass a pyramid as input, set the number of levels you want to scan and optionally set the scale factor. After scanning all levels and performing non-maximum suppression, the scale of the keypoints will be set by means of interpolation using the scale that maximizes a response measure and its adjacent scales.\n\n###### Parameters\n\n* `threshold: number`. An integer between `0` and `255`, inclusive. The larger the number, the \"stronger\" your keypoints will be. The smaller the number, the more keypoint you will get. Numbers between `20` and `50` are usually meaningful.\n* `levels: number`. The number of pyramid levels you want to use. Defaults to `1` (i.e., no pyramid is used). When using a pyramid, a value such as `7` is a reasonable choice.\n* `scaleFactor: number`. The scale factor between two consecutive levels of the pyramid. This is a value between `1` (exclusive) and `2` (inclusive). Defaults to the square root of two. This is applicable only when using a pyramid.\n* `capacity: number`. The maximum number of keypoints that can be detected by this node. The default capacity is `2048`. It can be no larger than `8192`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Greyscale image or pyramid. |\n| `\"out\"`   | Keypoints | Detected keypoints. |\n\n##### Speedy.Keypoint.Detector.Harris()\n\n`Speedy.Keypoint.Detector.Harris(name?: string): SpeedyPipelineNodeHarrisKeypointDetector`\n\nHarris corner detector. Speedy implements the Shi-Tomasi corner response for best results.\n\nTo use the multi-scale version of the algorithm, pass a pyramid as input, set the number of levels you want to scan and optionally set the scale factor. After scanning all levels and performing non-maximum suppression, the scale of the keypoints will be set by means of interpolation using the scale that maximizes a response measure and its adjacent scales.\n\n###### Parameters\n\n* `quality: number`. A value between `0` and `1` representing the minimum \"quality\" of the returned keypoints. Speedy will discard any keypoint whose score is lower than the specified percentage of the maximum keypoint score found in the image. A typical value for this parameter is `0.10` (10%).\n* `levels: number`. The number of pyramid levels you want to use. Defaults to `1` (i.e., no pyramid is used). When using a pyramid, a value such as `7` is a reasonable choice.\n* `scaleFactor: number`. The scale factor between two consecutive levels of the pyramid. This is a value between `1` (exclusive) and `2` (inclusive). Defaults to the square root of two. This is applicable only when using a pyramid.\n* `capacity: number`. The maximum number of keypoints that can be detected by this node. The default capacity is `2048`. It can be no larger than `8192`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | Greyscale image or pyramid. |\n| `\"out\"`   | Keypoints | Detected keypoints. |\n\n#### Keypoint description\n\n##### Speedy.Keypoint.Descriptor.ORB()\n\n`Speedy.Keypoint.Descriptor.ORB(name?: string): SpeedyPipelineNodeORBKeypointDescriptor`\n\nORB descriptors. In order to improve robustness to noise, apply a Gaussian filter to the image before computing the descriptors.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"image\"` | Image     | Input image. Must be greyscale. |\n| `\"keypoints\"` | Keypoints | Input keypoints. |\n| `\"out\"`   | Keypoints | Keypoints with descriptors. |\n\n###### Example\n\n```js\n/*\n\nThis is our pipeline:\n\nImage  ---\u003e Convert to ---\u003e Image ------\u003e FAST corner -----\u003e Keypoint ---\u003e ORB ----------\u003e Keypoint\nSource      greyscale       Pyramid       detector           Clipper       descriptors     Sink\n            |                                                               ^\n            |                                                               |\n            +-------------------------\u003e Gaussian ---------------------------+\n                                        Blur\n*/\n\nconst pipeline = Speedy.Pipeline();\nconst source = Speedy.Image.Source();\nconst greyscale = Speedy.Filter.Greyscale();\nconst pyramid = Speedy.Image.Pyramid();\nconst fast = Speedy.Keypoint.Detector.FAST();\nconst blur = Speedy.Filter.GaussianBlur();\nconst clipper = Speedy.Keypoint.Clipper();\nconst descriptor = Speedy.Keypoint.Descriptor.ORB();\nconst sink = Speedy.Keypoint.Sink();\n\nsource.media = media;\nblur.kernelSize = Speedy.Size(9, 9);\nblur.sigma = Speedy.Vector2(2, 2);\nfast.threshold = 50;\nfast.levels = 8; // pyramid levels\nfast.scaleFactor = 1.19; // approx. 2^0.25\nclipper.size = 800; // up to how many features?\n\nsource.output().connectTo(greyscale.input());\n\ngreyscale.output().connectTo(pyramid.input());\npyramid.output().connectTo(fast.input());\nfast.output().connectTo(clipper.input());\nclipper.output().connectTo(descriptor.input('keypoints'));\n\ngreyscale.output().connectTo(blur.input());\nblur.output().connectTo(descriptor.input('image'));\n\ndescriptor.output().connectTo(sink.input());\n\npipeline.init(source, greyscale, pyramid, blur, fast, clipper, descriptor, sink);\n```\n\n#### Keypoint tracking\n\nKeypoint tracking is the process of tracking keypoints across a sequence of images. It allows you to get a sense of how keypoints are moving in time - i.e., how fast they are moving and where they are going.\n\nSpeedy uses sparse optical-flow algorithms to track keypoints in a video. Applications of optical-flow are numerous: you may get a sense of how objects are moving in a scene, estimate how the camera itself is moving, detect a transition in a film (a cut between two shots), and so on.\n\n##### Speedy.Keypoint.SinkOfTrackedKeypoints()\n\n`Speedy.Keypoint.SinkOfTrackedKeypoints(name?: string): SpeedyPipelineNodeTrackedKeypointSink`\n\nCreates a sink of tracked keypoints using the specified name. If the name is not specified, Speedy will call this node `\"keypoints\"`. An array of `SpeedyTrackedKeypoint` objects will be exported from the pipeline.\n\nSee also: [SpeedyTrackedKeypoint](#SpeedyTrackedKeypoint).\n\n###### Parameters\n\nThe same as `SpeedyPipelineNodeKeypointSink`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints to be exported from the pipeline. |\n| `\"flow\"`  | Vector2   | A set of displacement vectors associated with each keypoint. |\n\n##### Speedy.Keypoint.Tracker.LK()\n\n`Speedy.Keypoint.Tracker.LK(name?: string): SpeedyPipelineNodeLKKeypointTracker`\n\nPyramid-based LK optical-flow.\n\n###### Parameters\n\n* `windowSize: SpeedySize`. The size of the window to be used by the feature tracker. The algorithm will read neighbor pixels to determine the motion of a keypoint. You must specify a square window. Typical sizes include: 7x7, 11x11, 15x15 (use positive odd integers). Defaults to 11x11.\n* `levels: number`. Specifies how many pyramid levels will be used in the computation. The more levels you use, the faster the motions you can capture. Defaults to `3`.\n* `discardThreshold: number`. A threshold used to discard keypoints that are not \"good\" candidates for tracking. The higher the value, the more keypoints will be discarded. Defaults to `0.0001`.\n* `numberOfIterations: number`. Maximum number of iterations for computing the local optical-flow on each level of the pyramid. Defaults to `30`.\n* `epsilon: number`. An accuracy threshold used to stop the computation of the local optical-flow of any level of the pyramid. The local optical-flow is computed iteratively and in small increments. If the length of an increment is too small, we discard it. This property defaults to `0.01`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"previousImage\"` | Image | Input image at time *t-1*. Must be greyscale. |\n| `\"nextImage\"` | Image | Input image at time *t*. Must be greyscale. |\n| `\"previousKeypoints\"` | Keypoints | Input keypoints at time *t-1*. |\n| `\"out\"` | Keypoints | Output keypoints at time *t*. |\n| `\"flow\"` | Vector2 | Flow vectors (output) at time *t*. |\n\n**Note**: you need to provide pyramids as input if `levels \u003e 1`.\n\n#### Keypoint matching\n\nKeypoint matching is the process of matching keypoints based on their descriptors. A distance metric is established in descriptor space. Two keypoints are said to be \"matched\" if the distance between their respective descriptors is minimized according to some criteria. Since Speedy uses binary descriptors, in practice we use the Hamming distance, i.e., the number of differing bits in two descriptors of same size.\n\nKeypoint matching is useful for object recognition, object tracking, rectification of images, and more.\n\n##### Speedy.Keypoint.SinkOfMatchedKeypoints()\n\n`Speedy.Keypoint.SinkOfMatchedKeypoints(name?: string): SpeedyPipelineNodeMatchedKeypointSink`\n\nCreate a sink of matched keypoints using the specified name. If the name is not specified, Speedy will call this node `\"keypoints\"`. An array of `SpeedyMatchedKeypoint` objects will be exported from the pipeline.\n\nSee also: [SpeedyMatchedKeypoint](#SpeedyMatchedKeypoint).\n\n###### Parameters\n\nThe same as `SpeedyPipelineNodeKeypointSink`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints to be exported from the pipeline. |\n| `\"matches\"` | KeypointMatches | A set of keypoint matches associated with each keypoint. |\n\n##### Speedy.Keypoint.Matcher.BFKNN()\n\n`Speedy.Keypoint.Matcher.BFKNN(name?: string): SpeedyPipelineNodeBruteForceKNNKeypointMatcher`\n\nBrute-force k-nearest neighbors keypoint matcher.\n\n###### Parameters\n\n* `k: number`. The desired number of matches per keypoint. Defaults to `1` (i.e., it will get you only the best match for each keypoint). Setting it to two gets you the first and the second best matches, and so on.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"keypoints\"` | Keypoints | The input keypoints that you want to match. |\n| `\"database\"` | Keypoints | A collection of keypoints to be matched against. |\n| `\"out\"` | KeypointMatches | The `k` best matches for all elements of `\"keypoints\"`. |\n\n**Note:** I suggest using brute-force to match two sets containing no more than a few hundreds of keypoints. Your mileage may vary. If you need to match thousands of keypoints or more, consider using an approximate matcher.\n\n**Note 2:** make sure that you use as input two sets of keypoints with the same type of descriptors.\n\n##### Speedy.Keypoint.Matcher.LSHKNN()\n\n`Speedy.Keypoint.Matcher.LSHKNN(name?: string): SpeedyPipelineNodeLSHKNNKeypointMatcher`\n\nFast approximate k-nearest neighbors keypoint matcher based on my own GPU-based variant of Locality Sensitive Hashing (LSH).\n\n###### Parameters\n\n* `k: number`. The desired number of matches per keypoint. Defaults to `1`.\n* `quality: string`. The desired quality level for the search of the best matches. One of the following: `\"default\"`, `\"fastest\"` or `\"demanding\"`. Changing this parameter impacts performance, and possibly the quality of the results.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"keypoints\"` | Keypoints | The input keypoints that you want to match. |\n| `\"lsh\"`   | LSHTables | LSH tables of the keypoints to be matched against (the \"database\"). |\n| `\"out\"`   | KeypointMatches | The `k` best matches (approximately) for all elements of `\"keypoints\"`. |\n\n**Tip:** the `\"default\"` `quality` is generally appropriate, but if you set it to `\"fastest\"`, consider increasing the number of LSH tables (see below).\n\n##### Speedy.Keypoint.Matcher.StaticLSHTables()\n\n`Speedy.Keypoint.Matcher.StaticLSHTables(name?: string): SpeedyPipelineNodeStaticLSHTables`\n\nGenerate LSH tables based on a known, and potentially large, collection of keypoints. LSH tables can help you match up to hundreds of thousands of keypoints.\n\n###### Parameters\n\n* `keypoints: SpeedyKeypoint[]`. The known collection of keypoints to be used as a \"database\" for matching. Make sure that they have descriptors.\n* `numberOfTables: number`. The number of LSH tables that you want to generate. Defaults to `8`. This parameter can be as low as `4` and as high as `32`. Increasing it may increase the quality of the results - at the expense of performance.\n* `hashSize: number`. The size of a descriptor hash, in bits. Defaults to `15`. This parameter can be as low as `10` and as high as `20`. Increasing it will substantially increase VRAM usage.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"out\"`   | LSHTables | LSH tables associated with the known collection of `keypoints`. |\n\n**Tip:** Speedy generates logs based on the numerical parameters that you define and on the number of keypoints in your database. You may use these logs to help you tune the numerical parameters. That being said, the default parameters are generally good.\n\n\n\n### Portals\n\nPortals let you create loops within a pipeline. They also let you transfer data between different pipelines.\n\nA portal is defined by a set of nodes: a portal sink and one or more portal sources. The portal sink receives data from a node of a pipeline, which is then read by the portal source(s). The portal source(s) feed(s) one or more pipelines. The portal nodes may or may not belong to the same pipeline.\n\n#### Image Portals\n\n##### Speedy.Image.Portal.Source()\n\n`Speedy.Image.Portal.Source(name?: string): SpeedyPipelineNodeImagePortalSource`\n\nCreate a source of an Image Portal.\n\n###### Parameters\n\n* `source: SpeedyPipelineNodeImagePortalSink`. A sink of an Image Portal.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"out\"`   | Image     | An image.   |\n\n##### Speedy.Image.Portal.Sink()\n\n`Speedy.Image.Portal.Sink(name?: string): SpeedyPipelineNodeImagePortalSink`\n\nCreate a sink of an Image Portal.\n\n**Note:** pyramids can't travel through portals at this time.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Image     | An image.   |\n\n#### Keypoint Portals\n\n##### Speedy.Keypoint.Portal.Source()\n\n`Speedy.Keypoint.Portal.Source(name?: string): SpeedyPipelineNodeKeypointPortalSource`\n\nCreate a source of a Keypoint Portal.\n\n###### Parameters\n\n* `source: SpeedyPipelineNodeKeypointPortalSink`. A sink of a Keypoint Portal.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"out\"`   | Keypoints | A set of keypoints. |\n\n##### Speedy.Keypoint.Portal.Sink()\n\n`Speedy.Keypoint.Portal.Sink(name?: string): SpeedyPipelineNodeKeypointPortalSink`\n\nCreate a sink of a Keypoint Portal.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Keypoints | A set of keypoints. |\n\n\n\n### Linear Algebra\n\nMatrix computations play a crucial role in computer vision applications. Speedy includes its own implementation of numerical linear algebra algorithms.\n\nMatrix operations are specified using a fluent interface that has been crafted to be easy to use and to mirror how we write matrix algebra using pen-and-paper.\n\nSince numerical algorithms may be computationally demanding, Speedy uses WebAssembly for extra performance. Most matrix-related routines are written in C language. Matrices are stored in [column-major format](https://en.wikipedia.org/wiki/Row-_and_column-major_order). Typed Arrays are used for storage.\n\nThere are two basic classes you need to be aware of: `SpeedyMatrix` and `SpeedyMatrixExpr`. The latter represents a symbolic expression, whereas the former represents an actual matrix with data. A `SpeedyMatrix` is a `SpeedyMatrixExpr`. A `SpeedyMatrixExpr` may be evaluated to a `SpeedyMatrix`.\n\n#### Creating new matrices\n\n##### Speedy.Matrix()\n\n`Speedy.Matrix(rows: number, columns: number, entries?: number[]): SpeedyMatrix`\n\n`Speedy.Matrix(expr: SpeedyMatrixExpr): SpeedyMatrix`\n\nFirst form: create a new matrix with the specified size and entries.\n\nSecond form: synchronously evaluate a matrix expression and store the result in a new matrix.\n\n###### Arguments\n\n* `rows: number`. The number of rows of the matrix.\n* `columns: number, optional`. The number of columns of the matrix. If not specified, it will be set to `rows` (i.e., you'll get a square matrix).\n* `entries: number[], optional`. The elements of the matrix in column-major format. The length of this array must be `rows * columns`.\n* `expr: SpeedyMatrixExpr`. The matrix expression to be evaluated.\n\n###### Returns\n\nA new `SpeedyMatrix`.\n\n###### Example\n\n```js\n//\n// We use the column-major format to specify\n// the elements of the new matrix. For example,\n// to create the 2x3 matrix (2 rows, 3 columns)\n// below, we first specify the elements of the\n// first column, then the elements of the second\n// column, and finally the elements of the third\n// column.\n// \n// M = [ 1  3  5 ]\n//     [ 2  4  6 ]\n//\nconst mat = Speedy.Matrix(2, 3, [\n    1,\n    2,\n        3,\n        4,\n            5,\n            6\n]);\n\n// Alternatively, we may write the data in\n// column-major format in a compact form:\nconst mat1 = Speedy.Matrix(2, 3, [\n    1, 2, // first column\n    3, 4, // second column\n    5, 6  // third column\n]);\n\n// Print the matrices to the console\nconsole.log(mat.toString());\nconsole.log(mat1.toString());\n```\n\n##### Speedy.Matrix.Zeros()\n\n`Speedy.Matrix.Zeros(rows: number, columns?: number): SpeedyMatrix`\n\nCreate a new matrix filled with zeros.\n\n###### Arguments\n\n* `rows: number`. The number of rows of the matrix.\n* `columns: number, optional`. The number of columns of the matrix. If not specified, it will be set to `rows` (square matrix).\n\n###### Returns\n\nA new `rows` x `columns` `SpeedyMatrix` filled with zeros.\n\n###### Example\n\n```js\n// A 3x3 matrix filled with zeros\nconst zeros = Speedy.Matrix.Zeros(3);\n```\n\n##### Speedy.Matrix.Ones()\n\n`Speedy.Matrix.Ones(rows: number, columns?: number): SpeedyMatrix`\n\nCreate a new matrix filled with ones.\n\n###### Arguments\n\n* `rows: number`. The number of rows of the matrix.\n* `columns: number, optional`. The number of columns of the matrix. If not specified, it will be set to `rows` (square matrix).\n\n###### Returns\n\nA new `rows` x `columns` `SpeedyMatrix` filled with ones.\n\n##### Speedy.Matrix.Eye()\n\n`Speedy.Matrix.Eye(rows: number, columns?: number): SpeedyMatrix`\n\nCreate a new matrix with ones on the main diagonal and zeros elsewhere.\n\n###### Arguments\n\n* `rows: number`. The number of rows of the matrix.\n* `columns: number, optional`. The number of columns of the matrix. If not specified, it will be set to `rows` (identity matrix).\n\n###### Returns\n\nA new `SpeedyMatrix` with the specified configuration.\n\n###### Example\n\n```js\n// A 3x3 identity matrix\nconst eye = Speedy.Matrix.Eye(3);\n```\n\n#### Matrix properties\n\n##### SpeedyMatrixExpr.rows\n\n`SpeedyMatrixExpr.rows: number, read-only`\n\nThe number of rows of the matrix expression.\n\n##### SpeedyMatrixExpr.columns\n\n`SpeedyMatrixExpr.columns: number, read-only`\n\nThe number of columns of the matrix expression.\n\n##### SpeedyMatrixExpr.dtype\n\n`SpeedyMatrixExpr.dtype: string, read-only`\n\nThe constant `\"float32\"`.\n\n##### SpeedyMatrix.data\n\n`SpeedyMatrix.data: ArrayBufferView, read-only`\n\nData storage.\n\n##### SpeedyMatrix.step\n\n`SpeedyMatrix.step0: number, read-only`\n\n`SpeedyMatrix.step1: number, read-only`\n\nStorage steps. The (`i`, `j`) entry of the matrix is stored at `data[i * step0 + j * step1]`.\n\n#### Reading from the matrices\n\n##### SpeedyMatrix.read()\n\n`SpeedyMatrix.read(): number[]`\n\nRead the entries of the matrix.\n\n###### Returns\n\nAn array containing the entries of the matrix in column-major format.\n\n###### Example\n\n```js\nconst mat = Speedy.Matrix(2, 2, [\n    1,\n    2,\n        3,\n        4\n]);\n\nconst entries = mat.read();\nconsole.log(entries); // [ 1, 2, 3, 4 ]\n```\n\n##### SpeedyMatrix.at()\n\n`SpeedyMatrix.at(row: number, column: number): number`\n\nRead a single entry of the matrix.\n\n###### Arguments\n\n* `row: number`. Index of the row of the desired element (0-based).\n* `column: number`. Index of the column of the desired element (0-based).\n\n###### Returns\n\nThe requested entry of the matrix, or a NaN if the entry is outside bounds.\n\n###### Example\n\n```js\nconst A = Speedy.Matrix(2, 2, [\n    1,\n    2,\n        3,\n        4\n]);\n\nconst a00 = A.at(0, 0); // first row, first column\nconst a10 = A.at(1, 0); // second row, first column\nconst a01 = A.at(0, 1); // first row, second column\nconst a11 = A.at(1, 1); // second row, second column\n\nconsole.log([ a00, a10, a01, a11 ]); // [ 1, 2, 3, 4 ]\n```\n\n##### SpeedyMatrixExpr.toString()\n\n`SpeedyMatrixExpr.toString(): string`\n\nConvert a matrix expression to a string. Entries will only be included if `this` expression is a `SpeedyMatrix`.\n\n###### Returns\n\nA string representation of the matrix expression.\n\n#### Writing to the matrices\n\n##### SpeedyMatrix.setTo()\n\n`SpeedyMatrix.setTo(expr: SpeedyMatrixExpr): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nEvaluate a matrix expression and store the result in `this` matrix.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. A matrix expression.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `this` matrix after evaluating `expr`.\n\n###### Example\n\n```js\n//\n// Let's add two matrices:\n//\n// A = [ 1  3 ]    B = [ 4  2 ]\n//     [ 2  4 ]        [ 3  1 ]\n//\n// We'll set C to the sum A + B\n//\nconst matA = Speedy.Matrix(2, 2, [\n    1, 2,\n    3, 4\n]);\nconst matB = Speedy.Matrix(2, 2, [\n    4, 3,\n    2, 1\n]);\n\n// Set C = A + B\nconst matC = Speedy.Matrix.Zeros(2, 2);\nawait matC.setTo(matA.plus(matB));\n\n//\n// Print the result:\n//\n// C = [ 5  5 ]\n//     [ 5  5 ]\n//\nconsole.log(matC.toString());\n```\n\n##### SpeedyMatrix.fill()\n\n`SpeedyMatrix.fill(value: number): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nFill `this` matrix with a scalar.\n\n###### Arguments\n\n* `value: number`. Scalar value.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `this` matrix.\n\n###### Example\n\n```js\n// Create a 5x5 matrix filled with twos\nconst twos = Speedy.Matrix.Zeros(5);\nawait twos.fill(2);\n```\n\n\n\n#### Synchronous writing\n\nSpeedy provides synchronous writing methods for convenience.\n\n##### Speedy.Matrix.ready()\n\n`Speedy.Matrix.ready(): SpeedyPromise\u003cvoid\u003e`\n\nThis method lets you know that the matrix routines are initialized and ready to be used (the WebAssembly routines need to be loaded before usage). You should only use the synchronous writing methods when the matrix routines are ready.\n\n###### Returns\n\nA `SpeedyPromise` that resolves immediately if the matrix routines are already initialized, or as soon as they are initialized.\n\n##### SpeedyMatrix.setToSync()\n\n`SpeedyMatrix.setToSync(expr: SpeedyMatrixExpr): SpeedyMatrix`\n\nSynchronously evaluate a matrix expression and store the result in `this` matrix.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. A matrix expression.\n\n###### Returns\n\nReturns `this` matrix after setting it to the result of `expr`.\n\n###### Example\n\n```js\nSpeedy.Matrix.ready().then(() =\u003e {\n    const mat = Speedy.Matrix.Eye(3); // I := identity matrix\n    const pot = 4; // power-of-two\n\n    for(let i = 0; i \u003c pot; i++)\n        mat.setToSync(mat.plus(mat)); // mat := mat + mat\n\n    console.log(mat.toString()); // mat will be (2^pot) * I\n});\n```\n\n##### SpeedyMatrix.fillSync()\n\n`SpeedyMatrix.fillSync(value: number): SpeedyMatrix`\n\nSynchronously fill `this` matrix with a scalar.\n\n###### Arguments\n\n* `value: number`. Scalar value.\n\n###### Returns\n\nReturns `this` matrix after filling it with the provided `value`.\n\n\n\n#### Access by block\n\nSpeedy lets you work with blocks of matrices. This is a very handy feature! Blocks share memory with the originating matrices. If you modify the entries of a block of a matrix *M*, you'll modify the corresponding entries of *M*. Columns and rows are examples of blocks.\n\n##### SpeedyMatrix.block()\n\n`SpeedyMatrix.block(firstRow: number, lastRow: number, firstColumn: number, lastColumn: number): SpeedyMatrix`\n\nExtract a `lastRow - firstRow + 1` x `lastColumn - firstColumn + 1` block from the matrix. All indices are 0-based. They are all inclusive. The memory of the matrix is shared with the block.\n\n###### Arguments\n\n* `firstRow: number`. Index of the first row (0-based).\n* `lastRow: number`. Index of the last row (0-based). Use `lastRow \u003e= firstRow`.\n* `firstColumn: number`. Index of the first column (0-based).\n* `lastColumn: number`. Index of the last column (0-based). Use `lastColumn \u003e= firstColumn`.\n\n###### Returns\n\nA new `SpeedyMatrix` representing the specified block.\n\n###### Example\n\n```js\n//\n// We'll create the following 4x4 matrix:\n// (a dot represents a zero)\n//\n// [ 5  5  5  . ]\n// [ 5  5  5  . ]\n// [ 5  5  5  . ]\n// [ .  .  .  . ]\n//\nconst mat = Speedy.Matrix.Zeros(4);\nawait mat.block(0, 2, 0, 2).fill(5);\nconsole.log(mat.toString());\n```\n\n##### SpeedyMatrix.column()\n\n`SpeedyMatrix.column(index: number): SpeedyMatrix`\n\nExtract a column of the matrix.\n\n###### Arguments\n\n* `index: number`. Index of the column (0-based).\n\n###### Returns\n\nA new `SpeedyMatrix` representing the specified column.\n\n###### Example\n\n```js\nconst mat = Speedy.Matrix(2, 3, [\n    1,\n    2,\n        3,\n        4,\n            5,\n            6\n]);\n\nconst firstColumn = mat.column(0); // [1, 2]^T\nconst secondColumn = mat.column(1); // [3, 4]^T\nconst thirdColumn = mat.column(2); // [5, 6]^T\n\nconsole.log(firstColumn.toString());\nconsole.log(secondColumn.toString());\nconsole.log(thirdColumn.toString());\n```\n\n##### SpeedyMatrix.row()\n\n`SpeedyMatrix.row(index: number): SpeedyMatrix`\n\nExtract a row of the matrix.\n\n###### Arguments\n\n* `index: number`. Index of the row (0-based).\n\n###### Returns\n\nA new `SpeedyMatrix` representing the specified row.\n\n###### Example\n\n```js\n//\n// We'll create the following matrix:\n// [ 0  0  0  0 ]\n// [ 1  1  1  1 ]\n// [ 2  2  2  2 ]\n// [ 0  0  0  0 ]\n//\nconst mat = Speedy.Matrix.Zeros(4);\nawait mat.row(1).fill(1);\nawait mat.row(2).fill(2);\nconsole.log(mat.toString());\n```\n\n##### SpeedyMatrix.diagonal()\n\n`SpeedyMatrix.diagonal(): SpeedyMatrix`\n\nExtract the main diagonal of `this` matrix as a column vector.\n\n###### Returns\n\nA new `SpeedyMatrix` representing the main diagonal of `this` matrix.\n\n###### Example\n\n```js\n//\n// We'll create the following matrix:\n// (a dot represents a zero)\n//\n// [ 5  .  .  .  . ]\n// [ .  5  .  .  . ]\n// [ .  .  5  .  . ]\n// [ .  .  .  .  . ]\n// [ .  .  .  .  . ]\n//\nconst mat = Speedy.Matrix.Zeros(5); // create a 5x5 matrix filled with zeros\nconst submat = mat.block(0, 2, 0, 2); // extract 3x3 submatrix at the \"top-left\"\nconst diag = submat.diagonal(); // extract the diagonal of the submatrix\n\nawait diag.fill(5); // fill the diagonal of the submatrix with a constant\nconsole.log(mat.toString()); // print the entire matrix\n\n// Alternatively, we may use this compact form:\nawait mat.block(0, 2, 0, 2).diagonal().fill(5);\n```\n\n#### Elementary operations\n\n##### SpeedyMatrixExpr.transpose()\n\n`SpeedyMatrixExpr.transpose(): SpeedyMatrixExpr`\n\nTranspose `this` matrix expression.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the tranpose of `this` matrix expression.\n\n###### Example\n\n```js\n// Create a 2x3 matrix\nconst mat = Speedy.Matrix(2, 3, [\n    1, 2, // first column\n    3, 4, // second column\n    5, 6  // third column\n]);\n\n// We'll store the transpose of mat in matT\nconst matT = Speedy.Matrix.Zeros(mat.columns, mat.rows);\nawait matT.setTo(mat.transpose());\n\n// Print the matrix and its transpose\nconsole.log(mat.toString());\nconsole.log(matT.toString());\n```\n\n##### SpeedyMatrixExpr.plus()\n\n`SpeedyMatrixExpr.plus(expr: SpeedyMatrixExpr): SpeedyMatrixExpr`\n\nCompute the sum between `this` matrix expression and `expr`. Both expressions must have the same shape.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. Another matrix expression.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the sum between `this` matrix expression and `expr`.\n\n###### Example\n\n```js\nconst matA = Speedy.Matrix(3, 3, [\n    1, 2, 3,\n    4, 5, 6,\n    7, 8, 9\n]);\nconst ones = Speedy.Matrix.Ones(3);\n\n// set B = A + 1\nconst matB = Speedy.Matrix.Zeros(3);\nawait matB.setTo(matA.plus(ones));\n```\n\n##### SpeedyMatrixExpr.minus()\n\n`SpeedyMatrixExpr.minus(expr: SpeedyMatrixExpr): SpeedyMatrixExpr`\n\nCompute the difference between `this` matrix expression and `expr`. Both expressions must have the same shape.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. Another matrix expression.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the difference between `this` matrix expression and `expr`.\n\n##### SpeedyMatrixExpr.times()\n\n`SpeedyMatrixExpr.times(expr: SpeedyMatrixExpr): SpeedyMatrixExpr`\n\n`SpeedyMatrixExpr.times(scalar: number): SpeedyMatrixExpr`\n\nMatrix multiplication.\n\nIn the first form, compute the matrix multiplication between `this` matrix expression and `expr`. The shape of `expr` must be compatible with the shape of `this` matrix expression.\n\nIn the second form, multiply `this` matrix expression by a `scalar`.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. Matrix expression.\n* `scalar: number`. A number.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the result of the multiplication.\n\n###### Example\n\n```js\nconst col = Speedy.Matrix(3, 1, [0, 5, 2]);\nconst row = Speedy.Matrix(1, 3, [1, 2, 3]);\n\nconst dot = row.times(col); // 1x1 matrix expression: inner product\nconst out = col.times(row); // 3x3 matrix expression: outer product\nconst len = col.transpose().times(col); // 1x1 matrix expression: squared length of col\n\nconst mat = Speedy.Matrix.Zeros(1);\nawait mat.setTo(len); // evaluate len\nconsole.log(mat.read()); // 29 = 0*0 + 5*5 + 2*2\n```\n\n##### SpeedyMatrixExpr.compMult()\n\n`SpeedyMatrixExpr.compMult(expr: SpeedyMatrixExpr): SpeedyMatrixExpr`\n\nCompute the component-wise multiplication between `this` matrix expression and `expr`. Both matrices must have the same shape.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. Matrix expression.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the component-wise multiplication.\n\n##### SpeedyMatrixExpr.inverse()\n\n`SpeedyMatrixExpr.inverse(): SpeedyMatrixExpr`\n\nCompute the inverse of `this` matrix expression. Make sure it's square.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the inverse of `this` matrix expression.\n\n##### SpeedyMatrixExpr.ldiv()\n\n`SpeedyMatrixExpr.ldiv(expr: SpeedyMatrixExpr): SpeedyMatrixExpr`\n\nLeft division `this` \\ `expr`. This is equivalent to solving a system of linear equations *Ax = b*, where *A* is `this` and *b* is `expr` (in a least squares sense if *A* is not square). The number of rows of `this` must be greater or equal than its number of columns. `expr` must be a column vector.\n\n###### Arguments\n\n* `expr: SpeedyMatrixExpr`. Matrix expression.\n\n###### Returns\n\nA `SpeedyMatrixExpr` representing the left division.\n\n\n\n#### Systems of equations\n\n##### Speedy.Matrix.solve()\n\n`Speedy.Matrix.solve(solution: SpeedyMatrix, A: SpeedyMatrix, b: SpeedyMatrix, options?: object): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nSolve a system of linear equations *Ax = b* for *x*, the `solution`, where `A` is a *n* x *n* square matrix, `b` is a *n* x *1* column vector and `solution` is a *n* x *1* column vector of unknowns. *n* is the number of equations and the number of unknowns.\n\n###### Arguments\n\n* `solution: SpeedyMatrix`. The output column vector.\n* `A: SpeedyMatrix`. A square matrix.\n* `b: SpeedyMatrix`. A column vector.\n* `options: object, optional`. Options to be passed to the solver. Available keys:\n    * `method: string`. One of the following: `\"qr\"`. Defaults to `\"qr\"`.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `solution`.\n\n###### Example\n\n```js\n//\n// We'll solve the following system of equations:\n// y - z = 9\n// y + z = 6\n//\n// Let's write it in matrix form:\n// [ 1  -1 ] [ y ] = [ 9 ]\n// [ 1   1 ] [ z ]   [ 6 ]\n//\n// The code below solves Ax = b for x, where\n// x = (y, z) is the column vector of unknowns.\n//\nconst A = Speedy.Matrix(2, 2, [\n    1, 1,  // first column\n    -1, 1  // second column\n]);\nconst b = Speedy.Matrix(2, 1, [\n    9, 6   // column vector\n]);\n\n// Solve Ax = b for x\nconst solution = Speedy.Matrix.Zeros(2, 1);\nawait Speedy.Matrix.solve(solution, A, b);\n\n// get the result\nconsole.log(solution.read()); // [ 7.5, -1.5 ]\n```\n\n##### Speedy.Matrix.ols()\n\n`Speedy.Matrix.ols(solution: SpeedyMatrix, A: SpeedyMatrix, b: SpeedyMatrix): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nOrdinary least squares.\n\nGiven an overdetermined system of linear equations *Ax = b*, where `A` is a *m* x *n* matrix, `b` is a *m* x *1* column vector and `solution` *x* is a *n* x 1 column vector of unknowns, find a `solution` *x* that minimizes the Euclidean norm of the residual *b - Ax*.\n\n*m* is the number of equations and *n* is the number of unknowns. We require *m* \u003e= *n*.\n\n###### Arguments\n\n* `solution: SpeedyMatrix`. The output column vector.\n* `A: SpeedyMatrix`. A matrix.\n* `b: SpeedyMatrix`. A column vector.\n* `options: object, optional`. Options to be passed to the solver. Available keys:\n    * `method: string`. One of the following: `\"qr\"`. Defaults to `\"qr\"`.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `solution`.\n\n\n\n#### Matrix factorization\n\n##### Speedy.Matrix.qr()\n\n`Speedy.Matrix.qr(Q: SpeedyMatrix, R: SpeedyMatrix, A: SpeedyMatrix, options?: object): SpeedyPromise\u003cvoid\u003e`\n\nCompute a QR decomposition of a *m* x *n* matrix `A` using Householder reflectors. `Q` will be orthogonal and `R` will be upper-triangular. We require *m* \u003e= *n*.\n\n###### Arguments\n\n* `Q: SpeedyMatrix`. Output matrix (*m* x *n* if reduced, *m* x *m* if full).\n* `R: SpeedyMatrix`. Output matrix (*n* x *n* if reduced, *m* x *n* if full).\n* `A: SpeedyMatrix`. The matrix to be decomposed.\n* `options: object, optional`. A configuration object that accepts the following keys:\n    * `mode: string`. Either `\"full\"` or `\"reduced\"`. Defaults to `\"reduced\"`.\n\n###### Returns\n\nReturns a `SpeedyPromise` that resolves as soon as the computation is complete.\n\n###### Example\n\n```js\n// We'll find a QR decomposition of this matrix\nconst A = Speedy.Matrix(3, 3, [\n    0, 1, 0, // first column\n    1, 1, 0, // second column\n    1, 2, 3, // third column\n]);\n\n// Compute a QR decomposition of A\nconst Q = Speedy.Matrix.Zeros(3, 3);\nconst R = Speedy.Matrix.Zeros(3, 3);\nawait Speedy.Matrix.qr(Q, R, A);\n\n// Print the result\nconsole.log(Q.toString());\nconsole.log(R.toString());\n\n// Check the answer (A = QR)\nconst QR = await Speedy.Matrix.Zeros(Q.rows, R.columns).setTo(Q.times(R));\nconsole.log(QR.toString());\n```\n\n\n\n### Geometric transformations\n\n#### Perspective transformation\n\n##### Speedy.Matrix.applyPerspectiveTransform()\n\n`Speedy.Matrix.applyPerspectiveTransform(dest: SpeedyMatrix, src: SpeedyMatrix, transform: SpeedyMatrix): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nApply a perspective `transform` to a set of 2D points described by `src` and store the results in `dest`.\n\n###### Arguments\n\n* `dest: SpeedyMatrix`. A 2 x *n* output matrix.\n* `src: SpeedyMatrix`. A 2 x *n* matrix encoding a set of *n* points, one per column.\n* `transform: SpeedyMatrix`. A 3x3 homography matrix.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `dest`.\n\n###### Example\n\n```js\nconst transform = Speedy.Matrix(3, 3, [\n    3, 0, 0, // first column\n    0, 2, 0, // second column\n    2, 1, 1, // third column\n]);\n\nconst src = Speedy.Matrix(2, 4, [\n    0, 0,\n    1, 0,\n    1, 1,\n    0, 1,\n]);\n\nconst dest = Speedy.Matrix.Zeros(src.rows, src.columns);\nawait Speedy.Matrix.applyPerspectiveTransform(dest, src, transform);\nconsole.log(dest.toString());\n\n//\n// Result:\n// [ 2  5  5  2 ]\n// [ 1  1  3  3 ]\n//\n```\n\n##### Speedy.Matrix.perspective()\n\n`Speedy.Matrix.perspective(homography: SpeedyMatrix, src: SpeedyMatrix, dest: SpeedyMatrix): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nCompute a `homography` matrix using four correspondences of points.\n\n###### Arguments\n\n* `homography: SpeedyMatrix`. A 3x3 output matrix.\n* `src: SpeedyMatrix`. A 2x4 matrix with the coordinates of four points (one per column) representing the corners of the source space.\n* `dest: SpeedyMatrix`. A 2x4 matrix with the coordinates of four points (one per column) representing the corners of the destination space.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `homography`.\n\n###### Example\n\n```js\nconst src = Speedy.Matrix(2, 4, [\n    0, 0, // first point\n    1, 0, // second point\n    1, 1, // third point\n    0, 1, // fourth point\n]);\n\nconst dest = Speedy.Matrix(2, 4, [\n    0, 0,\n    3, 0,\n    3, 2,\n    0, 2,\n]);\n\nconst homography = Speedy.Matrix.Zeros(3, 3);\nawait Speedy.Matrix.perspective(homography, src, dest);\n\nconsole.log(homography.toString());\n```\n\n##### Speedy.Matrix.findHomography()\n\n`Speedy.Matrix.findHomography(homography: SpeedyMatrix, src: SpeedyMatrix, dest: SpeedyMatrix, options?: object): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nCompute a `homography` matrix using a set of *n* \u003e= 4 correspondences of points, possibly with noise.\n\n###### Arguments\n\n* `homography: SpeedyMatrix`. A 3x3 output matrix.\n* `src: SpeedyMatrix`. A 2 x *n* matrix with the coordinates of *n* points (one per column) representing the corners of the source space.\n* `dest: SpeedyMatrix`. A 2 x *n* matrix with the coordinates of *n* points (one per column) representing the corners of the destination space.\n* `options: object, optional`. A configuration object.\n    * `method: string`. The method to be employed to compute the homography (see the table of methods below).\n\nTable of methods:\n\n| Method            | Description |\n|-------------------|-------------|\n| `\"default\"` | Normalized Direct Linear Transform (DLT). All points will be used to estimate the homography. Use this method if your data set is **not** polluted with outliers.\n| `\"pransac\"` | PRANSAC is a variant of RANSAC with bounded runtime that is designed for real-time tasks. It is able to reject outliers in the data set. |\n\nTable of parameters:\n\n| Parameter | Supported methods | Description |\n|-----------|-------------------|-------------|\n| `reprojectionError: number` | `\"pransac\"` | A threshold, measured in pixels, that lets Speedy decide if a data point is an inlier or an outlier for a given model. A data point is an inlier for a given model if the model maps its `src` coordinates near its `dest` coordinates (i.e., if the Euclidean distance is not greater than the threshold). A data point is an outlier if it's not an inlier. Defaults to 3 pixels. |\n| `mask: SpeedyMatrix` | `\"pransac\"` | An optional output matrix of shape 1 x *n*. Its i-th entry will be set to 1 if the i-th data point is an inlier for the best model found by the method, or 0 if it's an outlier. |\n| `numberOfHypotheses: number` | `\"pransac\"` | A positive integer specifying the number of models that will be generated and tested. The best model found by the method will be refined and then returned. If your inlier ratio is \"high\", this parameter can be set to a \"low\" number, making the algorithm run even faster. Defaults to 500. |\n| `bundleSize: number` | `\"pransac\"` | A positive integer specifying the number of data points to be tested against all viable models before the set of viable models gets cut in half, over and over again. Defaults to 100. |\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `homography`.\n\n###### Example\n\n```js\n//\n// Map random points\n// from [0,100] x [0,100]\n// to [200,600] x [200,600]\n//\nconst numPoints = 50;\nconst noiseLevel = 2;\n\nconst transform = x =\u003e 4*x + 200; // simulated model\nconst randCoord = () =\u003e 100 * Math.random(); // in [0, 100)\nconst randNoise = () =\u003e (Math.random() - 0.5) * noiseLevel;\n\nconst srcCoords = new Array(numPoints * 2).fill(0).map(() =\u003e randCoord());\nconst dstCoords = srcCoords.map(x =\u003e transform(x) + randNoise());\n\nconst src = Speedy.Matrix(2, numPoints, srcCoords);\nconst dst = Speedy.Matrix(2, numPoints, dstCoords);\nconst mask = Speedy.Matrix.Zeros(1, numPoints);\n\nconst homography = Speedy.Matrix.Zeros(3, 3);\nawait Speedy.Matrix.findHomography(homography, src, dst, {\n    method: \"pransac\",\n    mask: mask,\n    reprojectionError: 1\n});\n\nconsole.log('homography:', homography.toString());\nconsole.log('mask:', mask.toString());\n\n// Now let's test the homography using a few test points.\n// The points need to be mapped in line with our simulated model (see above)\nconst tstCoords = Speedy.Matrix(2, 5, [\n    0, 0,\n    100, 0,\n    100, 100,\n    0, 100,\n    50, 50,\n]);\n\nconst chkCoords = Speedy.Matrix.Zeros(2, 5);\nawait Speedy.Matrix.applyPerspectiveTransform(chkCoords, tstCoords, homography);\nconsole.log(chkCoords.toString());\n```\n\n\n#### Affine transformation\n\n##### Speedy.Matrix.applyAffineTransform()\n\n`Speedy.Matrix.applyAffineTransform(dest: SpeedyMatrix, src: SpeedyMatrix, transform: SpeedyMatrix): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nApply an affine `transform` to a set of 2D points described by `src` and store the results in `dest`.\n\n###### Arguments\n\n* `dest: SpeedyMatrix`. A 2 x *n* output matrix.\n* `src: SpeedyMatrix`. A 2 x *n* matrix encoding a set of *n* points, one per column.\n* `transform: SpeedyMatrix`. A 2x3 affine transformation matrix.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `dest`.\n\n###### Example\n\n```js\nconst transform = Speedy.Matrix(2, 3, [\n    3, 0, // first column\n    0, 2, // second column\n    2, 1, // third column\n]);\n\nconst src = Speedy.Matrix(2, 4, [\n    0, 0,\n    1, 0,\n    1, 1,\n    0, 1,\n]);\n\nconst dest = Speedy.Matrix.Zeros(src.rows, src.columns);\nawait Speedy.Matrix.applyAffineTransform(dest, src, transform);\nconsole.log(dest.toString());\n\n//\n// Result:\n// [ 2  5  5  2 ]\n// [ 1  1  3  3 ]\n//\n```\n\n##### Speedy.Matrix.affine()\n\n`Speedy.Matrix.affine(transform: SpeedyMatrix, src: SpeedyMatrix, dest: SpeedyMatrix): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nCompute an `affine` transform using three correspondences of points.\n\n###### Arguments\n\n* `transform: SpeedyMatrix`. A 2x3 output matrix.\n* `src: SpeedyMatrix`. A 2x3 matrix with the coordinates of three points (one per column) representing the corners of the source space.\n* `dest: SpeedyMatrix`. A 2x3 matrix with the coordinates of three points (one per column) representing the corners of the destination space.\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `transform`.\n\n###### Example\n\n```js\nconst src = Speedy.Matrix(2, 3, [\n    0, 0, // first point\n    1, 0, // second point\n    1, 1, // third point\n]);\n\nconst dest = Speedy.Matrix(2, 3, [\n    0, 0,\n    3, 0,\n    3, 2,\n]);\n\nconst transform = Speedy.Matrix.Zeros(2, 3);\nawait Speedy.Matrix.affine(transform, src, dest);\n\nconsole.log(transform.toString());\n```\n\n##### Speedy.Matrix.findAffineTransform()\n\n`Speedy.Matrix.findAffineTransform(transform: SpeedyMatrix, src: SpeedyMatrix, dest: SpeedyMatrix, options?: object): SpeedyPromise\u003cSpeedyMatrix\u003e`\n\nCompute an affine `transform` using a set of *n* \u003e= 3 correspondences of points, possibly with noise.\n\n###### Arguments\n\n* `transform: SpeedyMatrix`. A 2x3 output matrix.\n* `src: SpeedyMatrix`. A 2 x *n* matrix with the coordinates of *n* points (one per column) representing the corners of the source space.\n* `dest: SpeedyMatrix`. A 2 x *n* matrix with the coordinates of *n* points (one per column) representing the corners of the destination space.\n* `options: object, optional`. A configuration object.\n    * `method: string`. The method to be employed to compute the affine transform (see the table of methods below).\n\nTable of methods:\n\n* the same as [Speedy.Matrix.findHomography()](#speedymatrixfindhomography).\n\nTable of parameters:\n\n* the same as [Speedy.Matrix.findHomography()](#speedymatrixfindhomography).\n\n###### Returns\n\nA `SpeedyPromise` that resolves to `transform`.\n\n\n\n\n### Geometric Utilities\n\n#### 2D Vectors\n\n##### Speedy.Vector2()\n\n`Speedy.Vector2(x: number, y: number): SpeedyVector2`\n\nCreates a new 2D vector with the given coordinates.\n\n###### Arguments\n\n* `x: number`. The x-coordinate of the vector.\n* `y: number`. The y-coordinate of the vector.\n\n###### Returns\n\nA new `SpeedyVector2` instance.\n\n###### Example\n\n```js\nconst zero = Speedy.Vector2(0, 0);\n```\n\n##### Speedy.Vector2.Sink()\n\n`Speedy.Vector2.Sink(name?: string): SpeedyPipelineNodeVector2Sink`\n\nCreates a sink of 2D vectors using the specified name. If the name is not specified, Speedy will call this node `\"vec2\"`. An array of `SpeedyVector2` objects will be exported from the pipeline.\n\n###### Parameters\n\n* `turbo: boolean`. Accelerate GPU-CPU transfers. You'll get the data from the previous frame. Defaults to `false`.\n\n###### Ports\n\n| Port name | Data type | Description |\n|-----------|-----------|-------------|\n| `\"in\"`    | Vector2   | A set of 2D vectors to be exported from the pipeline. |\n\n##### SpeedyVector2.x\n\n`SpeedyVector2.x: number`\n\nThe x-coordinate of the vector.\n\n##### SpeedyVector2.y\n\n`SpeedyVector2.y: number`\n\nThe y-coordinate of the vector.\n\n##### SpeedyVector2.plus()\n\n`SpeedyVector2.plus(offset: SpeedyVector2): SpeedyVector2`\n\nVector addition.\n\n###### Returns\n\nA new vector corresponding to `this` + `offset`.\n\n##### SpeedyVector2.minus()\n\n`SpeedyVector2.minus(offset: SpeedyVector2): SpeedyVector2`\n\nVector subtraction.\n\n###### Returns\n\nA new vector corresponding to `this` - `offset`.\n\n##### SpeedyVector2.times()\n\n`SpeedyVector2.times(scalar: number): SpeedyVector2`\n\nMultiply a vector by a scalar.\n\n###### Returns\n\nA new vector corresponding to `this` * `scalar`.\n\n##### SpeedyVector2.length()\n\n`SpeedyVector2.length(): number`\n\nComputes the length of the vector (Euclidean norm).\n\n###### Returns\n\nThe length of the vector.\n\n###### Example\n\n```js\nconst v = Speedy.Vector2(3, 4);\n\nconsole.log('Coordinates', v.x, v.y);\nconsole.log('Length', v.length()); // 5\n```\n\n##### SpeedyVector2.normalized()\n\n`SpeedyVector2.normalized(): SpeedyVector2`\n\nReturns a normalized version of this vector.\n\n###### Returns\n\nA new vector with the same direction as the original one and with length equal to one.\n\n##### SpeedyVector2.dot()\n\n`SpeedyVector2.dot(v: SpeedyVector2): number`\n\nDot product.\n\n###### Arguments\n\n* `v: SpeedyVector2`. A vector.\n\n###### Returns\n\nThe dot product between the two vectors.\n\n##### SpeedyVector2.distanceTo()\n\n`SpeedyVector2.distanceTo(v: SpeedyVector2): number`\n\nComputes the distance between two vectors.\n\n###### Arguments\n\n* `v: SpeedyVector2`. A vector.\n\n###### Returns\n\nThe Euclidean distance between the two vectors.\n\n###### Example\n\n```js\nconst u = Speedy.Vector2(1, 0);\nconst v = Speedy.Vector2(5, 0);\n\nconsole.log(u.distanceTo(v)); // 4\n```\n\n##### SpeedyVector2.toString()\n\n`SpeedyVector2.toString(): string`\n\nGet a string representation of the vector.\n\n###### Returns\n\nA string representation of the vector.\n\n##### SpeedyVector2.equals()\n\n`SpeedyVector2.equals(v: SpeedyVector2): boolean`\n\nEquality comparison.\n\n###### Returns\n\nReturns `true` if the coordinates of `this` are equal to the coordinates of `v`, or `false` otherwise.\n\n#### 2D Points\n\n##### Speedy.Point2()\n\n`Speedy.Point2(x: number, y: number): SpeedyPoint2`\n\nCreates a new 2D point with the given coordinates.\n\n###### Arguments\n\n* `x: number`. The x-coordinate of the point.\n* `y: number`. The y-coordinate of the point.\n\n###### Returns\n\nA new `SpeedyPoint2` instance.\n\n###### Example\n\n```js\nconst p = Speedy.Point2(5, 10);\n```\n\n##### SpeedyPoint2.x\n\n`SpeedyPoint2.x: number`\n\nThe x-coordinate of the point.\n\n##### SpeedyPoint2.y\n\n`SpeedyPoint2.y: number`\n\nThe y-coordinate of the point.\n\n##### SpeedyPoint2.plus()\n\n`SpeedyPoint2.plus(v: SpeedyVector2): SpeedyPoint2`\n\nAdds a vector to this point.\n\n###### Arguments\n\n* `v: SpeedyVector2`. A 2D vector.\n\n###### Returns\n\nA new `SpeedyPoint2` instance corresponding to this point translated by `v`.\n\n##### SpeedyPoint2.minus()\n\n`SpeedyPoint2.minus(p: SpeedyPoint2): SpeedyVector2`\n\nSubtracts point `p` from this.\n\n###### Arguments\n\n* `p: SpeedyPoint2`. A 2D point.\n\n###### Returns\n\nA new `SpeedyVector2` instance such that `p` plus that vector equals this point.\n\n##### SpeedyPoint2.equals()\n\n`SpeedyPoint2.equals(p: SpeedyPoint2): boolean`\n\nEquality comparison.\n\n###### Returns\n\nReturns `true` if the coordinates of `this` are equal to the coordinates of `p`, or `false` otherwise.\n\n#### 2D Size\n\n##### Speedy.Size()\n\n`Speedy.Size(width: number, height: number): SpeedySize`\n\nCreates a new object that represents the size of a rectangle.\n\n###### Arguments\n\n* `width: number`. A non-negative number.\n* `height: number`. A non-negative number.\n\n###### Returns\n\nA new `SpeedySize` instance.\n\n###### Example\n\n```js\nconst size = Speedy.Size(640, 360);\n```\n\n##### SpeedySize.width\n\n`SpeedySize.width: number`\n\nWidth property.\n\n##### SpeedySize.height\n\n`SpeedySize.height: number`\n\nHeight property.\n\n##### SpeedySize.equals()\n\n`SpeedySize.equals(anotherSize: SpeedySize): boolean`\n\nChecks if two size objects have the same dimensions.\n\n###### Returns\n\nReturns `true` if the dimensions of `this` and `anotherSize` are equal.\n\n##### SpeedySize.toString()\n\n`SpeedySize.toString(): string`\n\nConvert to string.\n\n###### Returns\n\nA string representation of the object.\n\n\n\n\n\n\n### Extras\n\n#### Promises\n\nSpeedy includes its own implementation of Promises, called SpeedyPromises. SpeedyPromises can interoperate with standard ES6 Promises and are based on the [Promises/A+ specification](https://promisesaplus.com). The main difference between SpeedyPromises and standard ES6 Promises is that, under certain circunstances, SpeedyPromises can be made to run faster than ES6 Promises.\n\nSpeedyPromises are specially beneficial when you have a chain of them. When (and if) their \"turbocharged\" mode is invoked, they will adopt a special (non-standard) behavior and skip the microtask queue when settling promises in a chain. This will save you a few milliseconds. While \"a few milliseconds\" doesn't sound much in terms of standard web development, for a real-time library such as Speedy it means a lot. Simply put, we're squeezing out performance. SpeedyPromises are used internally by the library.\n\n##### Speedy.Promise\n\n`Speedy.Promise: Function`\n\nUsed to create a new `SpeedyPromise` object.\n\n###### Example\n\n```js\nlet promise = new Speedy.Promise((resolve, reject) =\u003e {\n    setTimeout(resolve, 2000);\n});\n\npromise.then(() =\u003e {\n    console.log(`The SpeedyPromise is now fulfilled.`);\n}).catch(() =\u003e {\n    console.log(`The SpeedyPromise is now rejected.`);\n}).finally(() =\u003e {\n    console.log(`The SpeedyPromise is now settled.`);\n});\n```\n\n\n\n#### Settings\n\nGlobal settings.\n\n##### Speedy.Settings.powerPreference\n\n`Speedy.Settings.powerPreference: \"default\" | \"low-power\" | \"high-performance\"`\n\n*Experimental*. The desired power preference for the WebGL context. This option should be set before creating any pipelines. The browser uses this setting as a hint to balance rendering performance and battery life (especially on mobile devices).\n\n##### Speedy.Settings.gpuPollingMode\n\n`Speedy.Settings.gpuPollingMode: \"raf\" | \"asap\"`\n\n*Experimental*. GPU polling mode. `\"asap\"` has slightly better performance than `\"raf\"`, at the cost of higher CPU usage.\n\n##### Speedy.Settings.logging\n\n`Speedy.Settings.logging: \"default\" | \"none\" | \"diagnostic\"`\n\nSpeedy prints messages to the browser console according to the logging mode. The table below summarizes the available modes:\n\n| Mode | Description |\n|------|-------------|\n| `\"default\"` | Shows warnings and some informative messages. |\n| `\"none\"`| Hides all messages. |\n| `\"diagnostic\"` | Enables the diagnostic mode, which lets you inspect the raw data traveling throughout the nodes of a pipeline. This has performance implications and is not meant to be used in production code. |\n\n\n\n\n#### Utilities\n\nExtra utilities.\n\n##### Speedy.version\n\n`Speedy.version: string, read-only`\n\nThe version of the library.\n\n##### Speedy.fps\n\n`Speedy.fps: number, read-only`\n\nSpeedy includes a frames per second (FPS) counter for testing purposes. It will be created as soon as you access it.\n\n###### Example\n\n```js\nconsole.log(Speedy.fps);\n```\n\n##### Speedy.isSupported()\n\n`Speedy.isSupported(): boolean`\n\nChecks if Speedy is supported in this machine \u0026 browser.\n\n###### Returns\n\nReturns a boolean telling whether or not Speedy is supported in the client environment.\n\n###### Example\n\n```js\nif(!Speedy.isSupported())\n    alert('This application is not supported in this browser. Please use a different browser.');\n```\n\n\n\n\n#### Platform\n\nUtilities to query information about the graphics driver. This information may or may not be available, depending on the privacy settings of the web browser. In addition, it may be more or less accurate in different browsers.\n\n##### Speedy.Platform.renderer\n\n`Speedy.Platform.renderer: string, read-only`\n\nRenderer string of the graphics driver.\n\n##### Speedy.Platform.vendor\n\n`Speedy.Platform.vendor: string, read-only`\n\nVendor string of the graphics driver.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falemart%2Fspeedy-vision","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falemart%2Fspeedy-vision","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falemart%2Fspeedy-vision/lists"}