From 452c0acc2c5a6f7f3febad215ebbc9b9fc3c45dc Mon Sep 17 00:00:00 2001 From: Thibault Durand Date: Thu, 4 Jun 2020 09:55:24 +0200 Subject: [PATCH 01/22] Evo: make DEFAULT_UNMATCHEDFRAMES_TOLERANCE and IOU_LIMIT configurable --- tracker.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tracker.js b/tracker.js index d96f3c2..d45cf63 100644 --- a/tracker.js +++ b/tracker.js @@ -226,6 +226,15 @@ exports.reset = function() { mapOfAllItemsTracked = new Map(); } +exports.setParams = function(params) { + if(params.unMatchedFramesTolerance) { + DEFAULT_UNMATCHEDFRAMES_TOLERANCE = params.unMatchedFramesTolerance; + } + if(params.iouLimit) { + IOU_LIMIT = params.iouLimit; + } +} + exports.enableKeepInMemory = function() { keepAllHistoryInMemory = true; } From 6e2e3dc749145c84612e9b77d747ce88da0c6ddb Mon Sep 17 00:00:00 2001 From: Thibault Durand Date: Thu, 4 Jun 2020 10:00:47 +0200 Subject: [PATCH 02/22] Tag 0.7.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f89fc4..29459a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.6.0", + "version": "0.7.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fdcc501..c871947 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.7.4", + "version": "0.7.5", "description": "Tracker by detections in javascript for node.js / browsers", "url": "https://github.com/tdurand/node-moving-things-tracker", "main": "main.js", From 638a04a5c2c6526117d3282b461f566cbcaabf49 Mon Sep 17 00:00:00 2001 From: Thibault Durand Date: Thu, 4 Jun 2020 10:41:44 +0200 Subject: [PATCH 03/22] Add little "How does it work section" --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 04e042c..cd428aa 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,21 @@ How to benchmark against MOT Challenge : https://github.com/opendatacam/node-mov No params tweaking is possible via command-line for now, it is currently optimized for tracking cars in traffic videos. +## How does it work + +Based on V-IOU tracker: https://github.com/bochinski/iou-tracker/ , paper: http://elvera.nue.tu-berlin.de/files/1547Bochinski2018.pdf + +In order to define if an object is the same from one frame to another, we compare the overlapping areas between the two detections between the frames. + +![screen shot 2017-10-18 at 15 57 25](https://user-images.githubusercontent.com/533590/31719755-295303c0-b41d-11e7-8059-3ff7bcefd722.png) + +By computing the intersection over union: + +![screen shot 2017-10-18 at 16 02 12](https://user-images.githubusercontent.com/533590/31719948-c6b69abe-b41d-11e7-8aac-5306e331f8b1.png) + +On top of this we added some prediction mecanism for next frame based on velocity / acceleration vector to avoid ID reassignment when the object is missed only for a few frames. + + ## License [MIT License](LICENSE) From 62bc0f0788ed37030d1322dc352e8e71f609ded4 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Mon, 10 Aug 2020 10:57:33 +0200 Subject: [PATCH 04/22] Feat(ItemTracked): Reset idDisplay Resetting the tracker now also resets the ID if tracked items. --- .gitignore | 4 + ItemTracked.js | 5 +- package-lock.json | 1142 +++++++++++++++++++++++++++++++++++++ package.json | 6 +- spec/ItemTracked.spec.js | 30 + spec/Tracker.spec.js | 60 ++ spec/support/jasmine.json | 11 + tracker.js | 20 +- 8 files changed, 1266 insertions(+), 12 deletions(-) create mode 100644 spec/ItemTracked.spec.js create mode 100644 spec/Tracker.spec.js create mode 100644 spec/support/jasmine.json diff --git a/.gitignore b/.gitignore index d7e4058..fe447ef 100644 --- a/.gitignore +++ b/.gitignore @@ -57,5 +57,9 @@ typings/ # dotenv environment variables file .env +# macOS System Files .DS_Store +.nosync +# Development Environment +.vscode diff --git a/ItemTracked.js b/ItemTracked.js index 5874467..c5e1e21 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -98,7 +98,7 @@ exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLE return this; } itemTracked.countDown = function(frameNb) { - // Set frame disappear number + // Set frame disappear number if(this.disappearFrame === null) { this.disappearFrame = frameNb; this.disappearArea = { @@ -212,3 +212,6 @@ exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLE return itemTracked; }; +exports.reset = function() { + idDisplay = 0; +} diff --git a/package-lock.json b/package-lock.json index 29459a6..348753e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,16 +4,1158 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jasmine": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.1.tgz", + "integrity": "sha512-Jqp8P6ZWkTVFGmJwBK46p+kJNrZCdqkQ4GL+PGuBXZwK1fM4ST9BizkYgIwCFqYYqnTizAy6+XG2Ej5dFrej9Q==", + "dev": true, + "requires": { + "fast-glob": "^2.2.6", + "jasmine-core": "~3.6.0" + } + }, + "jasmine-core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.6.0.tgz", + "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", diff --git a/package.json b/package.json index c871947..3219da5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "node-moving-things-tracker": "main.js" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jasmine" }, "author": "@tdurand", "contributors": [ @@ -20,5 +20,7 @@ "minimist": "^1.2.0", "uuid": "^3.2.1" }, - "devDependencies": {} + "devDependencies": { + "jasmine": "^3.6.1" + } } diff --git a/spec/ItemTracked.spec.js b/spec/ItemTracked.spec.js new file mode 100644 index 0000000..3044bd3 --- /dev/null +++ b/spec/ItemTracked.spec.js @@ -0,0 +1,30 @@ +const ItemTracked = require('../ItemTracked'); + +describe("ItemTracked", function () { + describe("idDisplay", function () { + const properties = { + x: null, + y: null, + w: null, + h: null, + name: "dummy", + confidence: null + }; + const item1 = ItemTracked.ItemTracked(properties); + const item2 = ItemTracked.ItemTracked(properties); + + it('starts at 0', function() { + expect(item1.idDisplay).toBe(0); + }); + + it('icrements IDs', function() { + expect(item1.idDisplay).toBeLessThan(item2.idDisplay); + }); + + it('resets IDs', function() { + ItemTracked.reset(); + const item3 = ItemTracked.ItemTracked(properties); + expect(item3.idDisplay).toBe(0); + }); + }); +}); diff --git a/spec/Tracker.spec.js b/spec/Tracker.spec.js new file mode 100644 index 0000000..9db0383 --- /dev/null +++ b/spec/Tracker.spec.js @@ -0,0 +1,60 @@ +const Tracker = require('../tracker'); + +const detections = [ + [ + { + x: 0.688212, + y: 0.755398, + w: 0.026031, + h: 0.048941, + confidence: 16.5444, + name: 'object' + } + ], + [ + { + x: 0.686925, + y: 0.796403, + w: 0.028142, + h: 0.050919, + confidence: 25.7651, + name: 'object' + } + ], + [ + { + x: 0.686721, + y: 0.837579, + w: 0.027887, + h: 0.054398, + confidence: 34.285399999999996, + name: 'object' + } + ], + [ + { + x: 0.686436, + y: 0.877328, + w: 0.026603, + h: 0.058, + confidence: 18.104300000000002, + name: 'object' + } + ] +]; + +describe('Tracker', function () { + describe('reset', function () { + it('resets ItemTracker idDisplay', function () { + detections.forEach((frame, frameNb) => { + Tracker.updateTrackedItemsWithNewFrame(frame, frameNb); + }); + + Tracker.reset(); + + Tracker.updateTrackedItemsWithNewFrame(detections[0], 0); + + expect(Tracker.getJSONOfTrackedItems()[0].id).toBe(0); + }); + }); +}); diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json new file mode 100644 index 0000000..370fc44 --- /dev/null +++ b/spec/support/jasmine.json @@ -0,0 +1,11 @@ +{ + "spec_dir": "spec", + "spec_files": [ + "**/*[sS]pec.js" + ], + "helpers": [ + "helpers/**/*.js" + ], + "stopSpecOnExpectationFailure": false, + "random": true +} diff --git a/tracker.js b/tracker.js index d45cf63..cbf2217 100644 --- a/tracker.js +++ b/tracker.js @@ -1,11 +1,12 @@ -var ItemTracked = require('./ItemTracked').ItemTracked; +const itemTrackedModule = require('./ItemTracked'); +var ItemTracked = itemTrackedModule.ItemTracked; var kdTree = require('./lib/kdTree-min.js').kdTree; var isEqual = require('lodash.isequal') var iouAreas = require('./utils').iouAreas var DEBUG_MODE = false; -// DEFAULT_UNMATCHEDFRAMES_TOLERANCE +// DEFAULT_UNMATCHEDFRAMES_TOLERANCE // This the number of frame we wait when an object isn't matched before considering it gone var DEFAULT_UNMATCHEDFRAMES_TOLERANCE = 5; // IOU_LIMIT, exclude things from beeing matched if their IOU is lower than this @@ -24,7 +25,7 @@ var mapOfAllItemsTracked = new Map(); // By default, we do not keep all the history in memory var keepAllHistoryInMemory = false; -// Implementation detail, we store the distance in a KDTREE, we want to be able to exclude values from +// Implementation detail, we store the distance in a KDTREE, we want to be able to exclude values from // the kdtree search by assigning them KDTREESEARCH_LIMIT + 1 var KDTREESEARCH_LIMIT = 10000; @@ -79,13 +80,13 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb // First predict the new position of the itemTracked var predictedPosition = itemTracked.predictNextPosition() - + // Make available for matching itemTracked.makeAvailable(); // Search for a detection that matches var treeSearchResult = treeDetectionsOfThisFrame.nearest(predictedPosition, 1, KDTREESEARCH_LIMIT)[0]; - + // Only for debug assessments of predictions var treeSearchResultWithoutPrediction = treeDetectionsOfThisFrame.nearest(itemTracked, 1, KDTREESEARCH_LIMIT)[0]; // Only if we enable the extra refinement @@ -124,7 +125,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb // var deltaAreaFirstChoice = Math.abs(detectionFirstChoice.area - itemTrackedArea) / (detectionFirstChoice.area + itemTrackedArea); // var deltaAreaSecondChoice = Math.abs(detectionSecondChoice.area - itemTrackedArea) / (detectionSecondChoice.area + itemTrackedArea); - // // Compare the area of each, priorize the detections that as a overal similar area + // // Compare the area of each, priorize the detections that as a overal similar area // // even if it overlaps less // if(deltaAreaFirstChoice > deltaAreaSecondChoice) { // if(Math.abs(deltaAreaFirstChoice - deltaAreaSecondChoice) > 0.5) { @@ -184,7 +185,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb matchedList.forEach(function(matched, index) { // Iterate through unmatched new detections if(!matched) { - // Do not add as new tracked item if it is to similar to an existing one + // Do not add as new tracked item if it is to similar to an existing one var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, KDTREESEARCH_LIMIT)[0]; if(!treeSearchResult) { @@ -202,7 +203,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb }); } - // Start killing the itemTracked (and predicting next position) + // Start killing the itemTracked (and predicting next position) // that are tracked but haven't been matched this frame mapOfItemsTracked.forEach(function(itemTracked) { if(itemTracked.available) { @@ -217,13 +218,14 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb } } }); - + } } exports.reset = function() { mapOfItemsTracked = new Map(); mapOfAllItemsTracked = new Map(); + itemTrackedModule.reset(); } exports.setParams = function(params) { From 34009aae3c8cf43965a422739ed75048226bb5cc Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Mon, 10 Aug 2020 10:58:21 +0200 Subject: [PATCH 05/22] Feat(Tests): Run Tests on GitHub Actions --- .github/workflows/node.js.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/node.js.yml diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..be06cde --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,26 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +# Trigger the workflow on push or pull request +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test From 853ffb16ea8f6d17f64ffa1a5c8a12ee6b1c9b3d Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Mon, 10 Aug 2020 12:04:15 +0200 Subject: [PATCH 06/22] Feat(Tracker): Configurable Fast Delete This allows to configure if detections should be removed quickly in cases where they were detected and could not be matched afterwards. Fast deletion can be enabled/disabled via ``` Tracker.setParams({ items: { fastDelete: false } }); ``` --- ItemTracked.js | 17 ++++++++++++++++- spec/Tracker.spec.js | 37 +++++++++++++++++++++++++++++++++---- tracker.js | 5 +++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/ItemTracked.js b/ItemTracked.js index c5e1e21..7fc87f4 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -15,6 +15,15 @@ var computeVelocityVector = require('./utils').computeVelocityVector // Use a simple incremental unique id for the display var idDisplay = 0; +// Default Params +const params = { + // Remove new objects fast if they could not be matched in the next frames. + // Setting this to false ensures the object will stick around at least + // DEFAULT_UNMATCHEDFRAMES_TOLERANCE frames, even if they could neven be + // matched in subsequent frames. + fastDelete: true +} + exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLERANCE){ var DEFAULT_UNMATCHEDFRAMES_TOLERANCE = DEFAULT_UNMATCHEDFRAMES_TOLERANCE; var itemTracked = {}; @@ -111,7 +120,7 @@ exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLE this.frameUnmatchedLeftBeforeDying--; this.isZombie = true; // If it was matched less than 1 time, it should die quick - if(this.nbTimeMatched <= 1) { + if(params.fastDelete && this.nbTimeMatched <= 1) { this.frameUnmatchedLeftBeforeDying = -1; } } @@ -215,3 +224,9 @@ exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLE exports.reset = function() { idDisplay = 0; } + +exports.setParams = function(newParams) { + if("fastDelete" in newParams) { + params.fastDelete = newParams.fastDelete; + } +} diff --git a/spec/Tracker.spec.js b/spec/Tracker.spec.js index 9db0383..8e363f3 100644 --- a/spec/Tracker.spec.js +++ b/spec/Tracker.spec.js @@ -11,6 +11,7 @@ const detections = [ name: 'object' } ], + [], // This empty frame ensure that the object will be removed if fastDelete is enabled. [ { x: 0.686925, @@ -44,12 +45,23 @@ const detections = [ ]; describe('Tracker', function () { + beforeEach(function () { + Tracker.reset(); + Tracker.setParams({ + items: { + fastDelete: true + }, + unMatchedFramesTolerance: 5, + iouLimit: 0.05 + }); + + detections.forEach((frame, frameNb) => { + Tracker.updateTrackedItemsWithNewFrame(frame, frameNb); + }); + }); + describe('reset', function () { it('resets ItemTracker idDisplay', function () { - detections.forEach((frame, frameNb) => { - Tracker.updateTrackedItemsWithNewFrame(frame, frameNb); - }); - Tracker.reset(); Tracker.updateTrackedItemsWithNewFrame(detections[0], 0); @@ -57,4 +69,21 @@ describe('Tracker', function () { expect(Tracker.getJSONOfTrackedItems()[0].id).toBe(0); }); }); + + describe('fast delete', function () { + it('removes items with fast delete', function () { + expect(Tracker.getJSONOfTrackedItems()[0].id).toBeGreaterThan(0); + }); + + it('keeps the item if fastDelete is disabled', function () { + Tracker.setParams({ items: { fastDelete: false } }); + Tracker.reset(); + + detections.forEach((frame, frameNb) => { + Tracker.updateTrackedItemsWithNewFrame(frame, frameNb); + }); + + expect(Tracker.getJSONOfTrackedItems()[0].id).toBe(0); + }); + }); }); diff --git a/tracker.js b/tracker.js index cbf2217..23f5cf1 100644 --- a/tracker.js +++ b/tracker.js @@ -235,6 +235,11 @@ exports.setParams = function(params) { if(params.iouLimit) { IOU_LIMIT = params.iouLimit; } + + // To keep the API simple, we just move the params down to the ItemsTracked as well. + if("items" in params) { + itemTrackedModule.setParams(params.items); + } } exports.enableKeepInMemory = function() { From ca648b875fae74efec2315ec45ff01fa6b74a678 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Mon, 10 Aug 2020 16:53:30 +0200 Subject: [PATCH 07/22] refactor(Tracker): FastDelete configurable per Item Allows to change fast detele for each item individually (e.g. based on confidence). --- ItemTracked.js | 18 +++++------------- spec/Tracker.spec.js | 6 ++---- tracker.js | 41 ++++++++++++++++++++--------------------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/ItemTracked.js b/ItemTracked.js index 7fc87f4..dcc54d7 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -15,25 +15,17 @@ var computeVelocityVector = require('./utils').computeVelocityVector // Use a simple incremental unique id for the display var idDisplay = 0; -// Default Params -const params = { - // Remove new objects fast if they could not be matched in the next frames. - // Setting this to false ensures the object will stick around at least - // DEFAULT_UNMATCHEDFRAMES_TOLERANCE frames, even if they could neven be - // matched in subsequent frames. - fastDelete: true -} - -exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLERANCE){ - var DEFAULT_UNMATCHEDFRAMES_TOLERANCE = DEFAULT_UNMATCHEDFRAMES_TOLERANCE; +exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fastDelete){ + var DEFAULT_UNMATCHEDFRAMES_TOLERANCE = unMatchedFramesTolerance; var itemTracked = {}; // ==== Private ===== // Am I available to be matched? itemTracked.available = true; // Should I be deleted? itemTracked.delete = false; + itemTracked.fastDelete = fastDelete; // How many unmatched frame should I survive? - itemTracked.frameUnmatchedLeftBeforeDying = DEFAULT_UNMATCHEDFRAMES_TOLERANCE; + itemTracked.frameUnmatchedLeftBeforeDying = unMatchedFramesTolerance; itemTracked.isZombie = false; itemTracked.appearFrame = frameNb; itemTracked.disappearFrame = null; @@ -120,7 +112,7 @@ exports.ItemTracked = function(properties, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLE this.frameUnmatchedLeftBeforeDying--; this.isZombie = true; // If it was matched less than 1 time, it should die quick - if(params.fastDelete && this.nbTimeMatched <= 1) { + if(this.fastDelete && this.nbTimeMatched <= 1) { this.frameUnmatchedLeftBeforeDying = -1; } } diff --git a/spec/Tracker.spec.js b/spec/Tracker.spec.js index 8e363f3..525c333 100644 --- a/spec/Tracker.spec.js +++ b/spec/Tracker.spec.js @@ -48,9 +48,7 @@ describe('Tracker', function () { beforeEach(function () { Tracker.reset(); Tracker.setParams({ - items: { - fastDelete: true - }, + fastDelete: true, unMatchedFramesTolerance: 5, iouLimit: 0.05 }); @@ -76,7 +74,7 @@ describe('Tracker', function () { }); it('keeps the item if fastDelete is disabled', function () { - Tracker.setParams({ items: { fastDelete: false } }); + Tracker.setParams({ fastDelete: false }); Tracker.reset(); detections.forEach((frame, frameNb) => { diff --git a/tracker.js b/tracker.js index 23f5cf1..051f554 100644 --- a/tracker.js +++ b/tracker.js @@ -6,12 +6,19 @@ var iouAreas = require('./utils').iouAreas var DEBUG_MODE = false; -// DEFAULT_UNMATCHEDFRAMES_TOLERANCE -// This the number of frame we wait when an object isn't matched before considering it gone -var DEFAULT_UNMATCHEDFRAMES_TOLERANCE = 5; -// IOU_LIMIT, exclude things from beeing matched if their IOU is lower than this -// 1 means total overlap whereas 0 means no overlap -var IOU_LIMIT = 0.05 +const params = { + // DEFAULT_UNMATCHEDFRAMES_TOLERANCE + // This the number of frame we wait when an object isn't matched before considering it gone + unMatchedFramesTolerance: 5, + // DEFAULT_IOU_LIMIT, exclude things from beeing matched if their IOU is lower than this + // 1 means total overlap whereas 0 means no overlap + iouLimit: 0.05, + // Remove new objects fast if they could not be matched in the next frames. + // Setting this to false ensures the object will stick around at least + // unMatchedFramesTolerance frames, even if they could neven be matched in + // subsequent frames. + fastDelete: true +} // A dictionary of itemTracked currently tracked // key: uuid @@ -40,7 +47,7 @@ const computeDistance = function(item1, item2) { var distance = 1 - iou; // If the overlap is iou < 0.95, exclude value - if(distance > (1 - IOU_LIMIT)) { + if(distance > (1 - params.iouLimit)) { distance = KDTREESEARCH_LIMIT + 1; } @@ -62,7 +69,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb if(mapOfItemsTracked.size === 0) { // Just add every detected item as item Tracked detectionsOfThisFrame.forEach(function(itemDetected) { - var newItemTracked = new ItemTracked(itemDetected, frameNb, DEFAULT_UNMATCHEDFRAMES_TOLERANCE) + var newItemTracked = new ItemTracked(itemDetected, frameNb, params.unMatchedFramesTolerance, params.fastDelete) // Add it to the map mapOfItemsTracked.set(newItemTracked.id, newItemTracked) // Add it to the kd tree @@ -189,7 +196,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, KDTREESEARCH_LIMIT)[0]; if(!treeSearchResult) { - var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, DEFAULT_UNMATCHEDFRAMES_TOLERANCE) + var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) // Add it to the map mapOfItemsTracked.set(newItemTracked.id, newItemTracked) // Add it to the kd tree @@ -228,18 +235,10 @@ exports.reset = function() { itemTrackedModule.reset(); } -exports.setParams = function(params) { - if(params.unMatchedFramesTolerance) { - DEFAULT_UNMATCHEDFRAMES_TOLERANCE = params.unMatchedFramesTolerance; - } - if(params.iouLimit) { - IOU_LIMIT = params.iouLimit; - } - - // To keep the API simple, we just move the params down to the ItemsTracked as well. - if("items" in params) { - itemTrackedModule.setParams(params.items); - } +exports.setParams = function(newParams) { + Object.keys(newParams).forEach((key) => { + params[key] = newParams[key]; + }); } exports.enableKeepInMemory = function() { From 473e6b8aee76a87dc3c4e26299322f7eaab9aabe Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Tue, 11 Aug 2020 11:41:37 +0200 Subject: [PATCH 08/22] Feat(Tracker): Allow for custom distance functions --- spec/Tracker.spec.js | 17 +++++++++++++++++ tracker.js | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/spec/Tracker.spec.js b/spec/Tracker.spec.js index 525c333..dd7d232 100644 --- a/spec/Tracker.spec.js +++ b/spec/Tracker.spec.js @@ -84,4 +84,21 @@ describe('Tracker', function () { expect(Tracker.getJSONOfTrackedItems()[0].id).toBe(0); }); }); + + describe('custom distance function', function() { + var distanceSpy; + beforeEach(function() { + distanceSpy = jasmine.createSpy('distance spy', Tracker.iouDistance); + + Tracker.reset(); + Tracker.setParams({ distanceFunc: distanceSpy }); + detections.forEach((frame, frameNb) => { + Tracker.updateTrackedItemsWithNewFrame(frame, frameNb); + }); + }); + + it('called the custom distance', function() { + expect(distanceSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/tracker.js b/tracker.js index 051f554..39cc23f 100644 --- a/tracker.js +++ b/tracker.js @@ -6,6 +6,23 @@ var iouAreas = require('./utils').iouAreas var DEBUG_MODE = false; +// Distance function +const iouDistance = function(item1, item2) { + // IOU distance, between 0 and 1 + // The smaller the less overlap + var iou = iouAreas(item1, item2); + + // Invert this as the KDTREESEARCH is looking for the smaller value + var distance = 1 - iou; + + // If the overlap is iou < 0.95, exclude value + if(distance > (1 - params.iouLimit)) { + distance = KDTREESEARCH_LIMIT + 1; + } + + return distance; +} + const params = { // DEFAULT_UNMATCHEDFRAMES_TOLERANCE // This the number of frame we wait when an object isn't matched before considering it gone @@ -17,7 +34,9 @@ const params = { // Setting this to false ensures the object will stick around at least // unMatchedFramesTolerance frames, even if they could neven be matched in // subsequent frames. - fastDelete: true + fastDelete: true, + // The function to use to determine the distance between to detected objects + distanceFunc: iouDistance } // A dictionary of itemTracked currently tracked @@ -37,33 +56,18 @@ var keepAllHistoryInMemory = false; var KDTREESEARCH_LIMIT = 10000; -// Distance function -const computeDistance = function(item1, item2) { - // IOU distance, between 0 and 1 - // The smaller the less overlap - var iou = iouAreas(item1, item2); - - // Invert this as the KDTREESEARCH is looking for the smaller value - var distance = 1 - iou; - // If the overlap is iou < 0.95, exclude value - if(distance > (1 - params.iouLimit)) { - distance = KDTREESEARCH_LIMIT + 1; - } - - return distance; -} -exports.computeDistance = computeDistance; +exports.computeDistance = iouDistance; exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb) { // A kd-tree containing all the itemtracked // Need to rebuild on each frame, because itemTracked positions have changed - var treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), computeDistance, ["x", "y", "w", "h"]); + var treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), params.distanceFunc, ["x", "y", "w", "h"]); // Contruct a kd tree for the detections of this frame - var treeDetectionsOfThisFrame = new kdTree(detectionsOfThisFrame, computeDistance, ["x", "y", "w", "h"]); + var treeDetectionsOfThisFrame = new kdTree(detectionsOfThisFrame, params.distanceFunc, ["x", "y", "w", "h"]); // SCENARIO 1: itemsTracked map is empty if(mapOfItemsTracked.size === 0) { @@ -187,7 +191,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb // to existing trackedItems this avoids adding some double match of YOLO and bring down drasticly reassignments if(mapOfItemsTracked.size > 0) { // Safety check to see if we still have object tracked (could have been deleted previously) // Rebuild tracked item tree to take in account the new positions - treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), computeDistance, ["x", "y", "w", "h"]); + treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), params.distanceFunc, ["x", "y", "w", "h"]); // console.log(`Nb new items Unmatched : ${matchedList.filter((isMatched) => isMatched === false).length}`) matchedList.forEach(function(matched, index) { // Iterate through unmatched new detections From 35669b3672711c4c917ba3cf72e4142ef0d8ba75 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Tue, 11 Aug 2020 12:02:58 +0200 Subject: [PATCH 09/22] chore(ItemTracked): Removes unused function --- ItemTracked.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ItemTracked.js b/ItemTracked.js index dcc54d7..dea1160 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -216,9 +216,3 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa exports.reset = function() { idDisplay = 0; } - -exports.setParams = function(newParams) { - if("fastDelete" in newParams) { - params.fastDelete = newParams.fastDelete; - } -} From 68eb9a4c864267401562cc10beb675693fbd3423 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Mon, 17 Aug 2020 10:41:25 +0200 Subject: [PATCH 10/22] Refactor(tracker): Allow setting distance limit This is useful to set the distance limit when setting a custom distance function. --- spec/Tracker.spec.js | 22 ++++++++++++++++++++++ tracker.js | 21 +++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/spec/Tracker.spec.js b/spec/Tracker.spec.js index dd7d232..e2cd6ef 100644 --- a/spec/Tracker.spec.js +++ b/spec/Tracker.spec.js @@ -101,4 +101,26 @@ describe('Tracker', function () { expect(distanceSpy).toHaveBeenCalled(); }); }); + + describe('distance limit', function() { + const d1 = detections[0][0]; + const d2 = detections[2][0]; + const params = { distanceLimit: 20000 }; + + beforeAll(function() { + Tracker.setParams(params); + }); + + it('is under limit if match successful', function() { + expect(Tracker.computeDistance(d1, d2)).toBeLessThanOrEqual(params.distanceLimit); + }); + + it('is above distance limit if match fails', function() { + Tracker.setParams({ + distanceLimit: params.distanceLimit, + iouLimit: 0.99 + }); + expect(Tracker.computeDistance(d1, d2)).toBeGreaterThan(params.distanceLimit); + }) + }); }); diff --git a/tracker.js b/tracker.js index 39cc23f..8c7f762 100644 --- a/tracker.js +++ b/tracker.js @@ -17,7 +17,7 @@ const iouDistance = function(item1, item2) { // If the overlap is iou < 0.95, exclude value if(distance > (1 - params.iouLimit)) { - distance = KDTREESEARCH_LIMIT + 1; + distance = params.distanceLimit + 1; } return distance; @@ -36,7 +36,10 @@ const params = { // subsequent frames. fastDelete: true, // The function to use to determine the distance between to detected objects - distanceFunc: iouDistance + distanceFunc: iouDistance, + // The distance limit for matching. If values need to be excluded from + // matching set their distance to something greater than the distance limit + distanceLimit: 10000 } // A dictionary of itemTracked currently tracked @@ -51,12 +54,6 @@ var mapOfAllItemsTracked = new Map(); // By default, we do not keep all the history in memory var keepAllHistoryInMemory = false; -// Implementation detail, we store the distance in a KDTREE, we want to be able to exclude values from -// the kdtree search by assigning them KDTREESEARCH_LIMIT + 1 -var KDTREESEARCH_LIMIT = 10000; - - - exports.computeDistance = iouDistance; @@ -96,12 +93,12 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb itemTracked.makeAvailable(); // Search for a detection that matches - var treeSearchResult = treeDetectionsOfThisFrame.nearest(predictedPosition, 1, KDTREESEARCH_LIMIT)[0]; + var treeSearchResult = treeDetectionsOfThisFrame.nearest(predictedPosition, 1, params.distanceLimit)[0]; // Only for debug assessments of predictions - var treeSearchResultWithoutPrediction = treeDetectionsOfThisFrame.nearest(itemTracked, 1, KDTREESEARCH_LIMIT)[0]; + var treeSearchResultWithoutPrediction = treeDetectionsOfThisFrame.nearest(itemTracked, 1, params.distanceLimit)[0]; // Only if we enable the extra refinement - var treeSearchMultipleResults = treeDetectionsOfThisFrame.nearest(predictedPosition, 2, KDTREESEARCH_LIMIT); + var treeSearchMultipleResults = treeDetectionsOfThisFrame.nearest(predictedPosition, 2, params.distanceLimit); // If we have found something if(treeSearchResult) { @@ -197,7 +194,7 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb // Iterate through unmatched new detections if(!matched) { // Do not add as new tracked item if it is to similar to an existing one - var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, KDTREESEARCH_LIMIT)[0]; + var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, params.distanceLimit)[0]; if(!treeSearchResult) { var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) From 0589ea700811aaef930bd962ba56f6125b78d020 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Tue, 8 Sep 2020 10:44:42 +0200 Subject: [PATCH 11/22] Adds @vsaw as contributor and bumps version to 0.8.0 --- package-lock.json | 2 +- package.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 348753e..5ef2371 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.7.5", + "version": "0.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3219da5..ee440c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.7.5", + "version": "0.8.0", "description": "Tracker by detections in javascript for node.js / browsers", "url": "https://github.com/tdurand/node-moving-things-tracker", "main": "main.js", @@ -12,7 +12,8 @@ }, "author": "@tdurand", "contributors": [ - "Benedikt Groß (http://benedikt-gross.de/)" + "Benedikt Groß (http://benedikt-gross.de/)", + "Valentin Sawadski (https://github.com/vsaw/)" ], "license": "MIT", "dependencies": { From 1d4f103b293d294767c77d91953f33868b8d20f1 Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Wed, 23 Jun 2021 23:39:27 +0200 Subject: [PATCH 12/22] Add script to run full MOT17 benchmark --- .gitignore | 3 +++ benchmark.sh | 15 +++++++++++++++ documentation/BENCHMARK.md | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100755 benchmark.sh diff --git a/.gitignore b/.gitignore index fe447ef..b7fb5b4 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,6 @@ typings/ # Development Environment .vscode + +MOT17Labels.zip +benchmark/MOT17/ diff --git a/benchmark.sh b/benchmark.sh new file mode 100755 index 0000000..2ac3873 --- /dev/null +++ b/benchmark.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +if [ ! -d "benchmark" ]; then + wget -nc https://motchallenge.net/data/MOT17Labels.zip + unzip MOT17Labels.zip "train/*" -d "benchmark" && mv "benchmark/train" "benchmark/MOT17" +fi + +for d in benchmark/MOT17/*/ ; do + node main.js --mode motchallenge --input "${d}det/det.txt" && \ + mv "${d}/det/outputTrackerMOT.txt" "benchmark/MOT17/$(basename ${d}).txt" +done + +pushd benchmark/MOT17 +python3 -m motmetrics.apps.eval_motchallenge . . +popd diff --git a/documentation/BENCHMARK.md b/documentation/BENCHMARK.md index 485d227..5759c55 100644 --- a/documentation/BENCHMARK.md +++ b/documentation/BENCHMARK.md @@ -66,3 +66,39 @@ python3 -m motmetrics.apps.eval_motchallenge . . MOT17-04-DPM 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 OVERALL 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 ``` + +### Run full benchmark + +In order to benchmark the tracker on all MOT17 training sequences, delete the directory `benchmark` and run + +```bash +./benchmark.sh +``` + +On the first run, the script will download the full MOT17 training benchmark and unpack it. Then, it runs the tracker on each sequence and outputs the evaluation metrics. + +``` + IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm +MOT17-04-SDP 62.1% 74.7% 53.2% 69.1% 97.0% 83 32 39 12 1018 14708 138 381 66.6% 0.152 82 61 11 +MOT17-04-DPM 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 110 240 10 +MOT17-05-DPM 34.2% 45.9% 27.3% 41.7% 70.1% 133 9 68 56 1227 4035 131 182 22.0% 0.258 101 57 34 +MOT17-05-FRCNN 45.0% 60.4% 35.9% 52.3% 87.9% 133 24 64 45 498 3302 74 79 44.0% 0.173 83 27 36 +MOT17-11-FRCNN 55.1% 72.8% 44.4% 55.7% 91.5% 75 15 36 24 491 4177 57 59 49.9% 0.097 37 33 13 +MOT17-05-SDP 43.2% 52.7% 36.6% 59.2% 85.2% 133 32 75 26 712 2823 102 146 47.4% 0.167 109 36 43 +MOT17-02-FRCNN 31.5% 52.4% 22.6% 34.8% 80.7% 62 6 25 31 1547 12123 107 138 25.9% 0.127 59 60 12 +MOT17-09-FRCNN 43.5% 60.8% 33.8% 53.6% 96.4% 26 6 16 4 107 2473 41 42 50.8% 0.096 27 19 5 +MOT17-10-FRCNN 39.5% 45.3% 35.0% 58.6% 75.8% 57 15 35 7 2395 5318 279 342 37.8% 0.164 156 124 13 +MOT17-04-FRCNN 49.5% 67.6% 39.0% 53.2% 92.4% 83 17 43 23 2092 22240 105 101 48.6% 0.108 42 67 4 +MOT17-13-DPM 27.4% 38.9% 21.1% 28.6% 52.6% 110 11 44 55 3000 8313 164 292 1.4% 0.282 50 126 16 +MOT17-13-SDP 59.4% 74.9% 49.3% 55.2% 83.9% 110 44 28 38 1235 5210 133 238 43.5% 0.213 82 71 25 +MOT17-02-SDP 34.0% 45.5% 27.1% 45.3% 76.0% 62 9 35 18 2663 10166 233 401 29.7% 0.202 117 122 10 +MOT17-13-FRCNN 49.3% 57.6% 43.1% 57.0% 76.4% 110 35 49 26 2053 5001 275 322 37.0% 0.172 160 137 33 +MOT17-02-DPM 23.0% 42.1% 15.8% 26.5% 70.5% 62 4 20 38 2063 13662 168 270 14.5% 0.261 65 108 7 +MOT17-10-SDP 48.4% 55.5% 42.9% 67.8% 87.8% 57 23 30 4 1211 4138 198 315 56.8% 0.205 114 84 5 +MOT17-09-DPM 34.2% 34.0% 34.4% 58.0% 57.3% 26 5 19 2 2303 2238 84 164 13.1% 0.275 49 39 7 +MOT17-09-SDP 48.2% 62.0% 39.4% 58.0% 91.4% 26 8 16 2 292 2239 52 83 51.5% 0.150 37 23 8 +MOT17-10-DPM 30.0% 36.6% 25.4% 42.8% 61.7% 57 7 30 20 3411 7339 219 388 14.6% 0.266 65 158 9 +MOT17-11-DPM 44.1% 48.4% 40.5% 53.8% 64.3% 75 11 32 32 2820 4361 68 82 23.2% 0.225 27 44 6 +MOT17-11-SDP 53.0% 62.1% 46.2% 66.8% 89.8% 75 20 38 17 715 3135 76 112 58.4% 0.149 44 41 13 +OVERALL 42.9% 54.6% 35.4% 51.3% 79.2% 1638 341 785 512 45411 164211 3059 4686 36.9% 0.175 1616 1677 320 +``` From aab43a6678952f512a2d0a2fa79a9c06c924c56f Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Wed, 23 Jun 2021 23:47:35 +0200 Subject: [PATCH 13/22] Remove short trajectories in MOT17 benchmark --- documentation/BENCHMARK.md | 50 +++++++++++++++++++------------------- main.js | 10 ++++++++ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/documentation/BENCHMARK.md b/documentation/BENCHMARK.md index 5759c55..633c6d3 100644 --- a/documentation/BENCHMARK.md +++ b/documentation/BENCHMARK.md @@ -62,9 +62,9 @@ python3 -m motmetrics.apps.eval_motchallenge . . - Result ``` - IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP -MOT17-04-DPM 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 -OVERALL 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 + IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm +MOT17-04-DPM 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 +OVERALL 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 ``` ### Run full benchmark @@ -79,26 +79,26 @@ On the first run, the script will download the full MOT17 training benchmark and ``` IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm -MOT17-04-SDP 62.1% 74.7% 53.2% 69.1% 97.0% 83 32 39 12 1018 14708 138 381 66.6% 0.152 82 61 11 -MOT17-04-DPM 28.6% 34.4% 24.5% 42.8% 60.0% 83 8 43 32 13558 27210 355 549 13.5% 0.224 110 240 10 -MOT17-05-DPM 34.2% 45.9% 27.3% 41.7% 70.1% 133 9 68 56 1227 4035 131 182 22.0% 0.258 101 57 34 -MOT17-05-FRCNN 45.0% 60.4% 35.9% 52.3% 87.9% 133 24 64 45 498 3302 74 79 44.0% 0.173 83 27 36 -MOT17-11-FRCNN 55.1% 72.8% 44.4% 55.7% 91.5% 75 15 36 24 491 4177 57 59 49.9% 0.097 37 33 13 -MOT17-05-SDP 43.2% 52.7% 36.6% 59.2% 85.2% 133 32 75 26 712 2823 102 146 47.4% 0.167 109 36 43 -MOT17-02-FRCNN 31.5% 52.4% 22.6% 34.8% 80.7% 62 6 25 31 1547 12123 107 138 25.9% 0.127 59 60 12 -MOT17-09-FRCNN 43.5% 60.8% 33.8% 53.6% 96.4% 26 6 16 4 107 2473 41 42 50.8% 0.096 27 19 5 -MOT17-10-FRCNN 39.5% 45.3% 35.0% 58.6% 75.8% 57 15 35 7 2395 5318 279 342 37.8% 0.164 156 124 13 -MOT17-04-FRCNN 49.5% 67.6% 39.0% 53.2% 92.4% 83 17 43 23 2092 22240 105 101 48.6% 0.108 42 67 4 -MOT17-13-DPM 27.4% 38.9% 21.1% 28.6% 52.6% 110 11 44 55 3000 8313 164 292 1.4% 0.282 50 126 16 -MOT17-13-SDP 59.4% 74.9% 49.3% 55.2% 83.9% 110 44 28 38 1235 5210 133 238 43.5% 0.213 82 71 25 -MOT17-02-SDP 34.0% 45.5% 27.1% 45.3% 76.0% 62 9 35 18 2663 10166 233 401 29.7% 0.202 117 122 10 -MOT17-13-FRCNN 49.3% 57.6% 43.1% 57.0% 76.4% 110 35 49 26 2053 5001 275 322 37.0% 0.172 160 137 33 -MOT17-02-DPM 23.0% 42.1% 15.8% 26.5% 70.5% 62 4 20 38 2063 13662 168 270 14.5% 0.261 65 108 7 -MOT17-10-SDP 48.4% 55.5% 42.9% 67.8% 87.8% 57 23 30 4 1211 4138 198 315 56.8% 0.205 114 84 5 -MOT17-09-DPM 34.2% 34.0% 34.4% 58.0% 57.3% 26 5 19 2 2303 2238 84 164 13.1% 0.275 49 39 7 -MOT17-09-SDP 48.2% 62.0% 39.4% 58.0% 91.4% 26 8 16 2 292 2239 52 83 51.5% 0.150 37 23 8 -MOT17-10-DPM 30.0% 36.6% 25.4% 42.8% 61.7% 57 7 30 20 3411 7339 219 388 14.6% 0.266 65 158 9 -MOT17-11-DPM 44.1% 48.4% 40.5% 53.8% 64.3% 75 11 32 32 2820 4361 68 82 23.2% 0.225 27 44 6 -MOT17-11-SDP 53.0% 62.1% 46.2% 66.8% 89.8% 75 20 38 17 715 3135 76 112 58.4% 0.149 44 41 13 -OVERALL 42.9% 54.6% 35.4% 51.3% 79.2% 1638 341 785 512 45411 164211 3059 4686 36.9% 0.175 1616 1677 320 +MOT17-04-SDP 62.2% 74.8% 53.2% 69.0% 97.1% 83 32 39 12 982 14737 121 367 66.7% 0.152 82 46 12 +MOT17-04-DPM 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 +MOT17-05-DPM 34.3% 48.2% 26.7% 40.2% 72.8% 133 9 63 61 1040 4133 94 150 23.9% 0.257 101 27 39 +MOT17-05-FRCNN 44.8% 61.3% 35.3% 51.6% 89.6% 133 24 56 53 414 3347 63 69 44.7% 0.172 82 20 39 +MOT17-11-FRCNN 55.4% 74.2% 44.2% 55.3% 92.8% 75 15 34 26 405 4219 45 50 50.5% 0.096 35 22 12 +MOT17-05-SDP 43.1% 53.9% 35.9% 58.0% 87.0% 133 31 64 38 597 2905 84 128 48.2% 0.165 108 21 45 +MOT17-02-FRCNN 31.6% 52.8% 22.6% 34.6% 81.1% 62 6 25 31 1502 12148 93 127 26.0% 0.126 55 49 11 +MOT17-09-FRCNN 43.6% 61.2% 33.8% 53.4% 96.8% 26 6 16 4 95 2481 37 39 50.9% 0.096 27 16 6 +MOT17-10-FRCNN 40.0% 46.8% 35.0% 57.9% 77.6% 57 15 35 7 2150 5405 228 311 39.4% 0.162 147 89 16 +MOT17-04-FRCNN 49.5% 67.8% 39.0% 53.2% 92.4% 83 17 43 23 2077 22271 93 90 48.6% 0.108 42 56 5 +MOT17-13-DPM 28.8% 45.8% 21.0% 27.1% 59.2% 110 10 42 58 2172 8489 75 207 7.8% 0.282 48 42 19 +MOT17-13-SDP 60.3% 78.0% 49.1% 54.5% 86.6% 110 43 25 42 980 5294 72 199 45.5% 0.212 70 24 27 +MOT17-02-SDP 34.3% 46.8% 27.1% 44.7% 77.1% 62 9 34 19 2468 10275 176 353 30.5% 0.201 114 72 13 +MOT17-13-FRCNN 50.4% 61.1% 42.9% 55.9% 79.6% 110 35 46 29 1667 5129 200 259 39.9% 0.169 141 83 34 +MOT17-02-DPM 23.3% 44.5% 15.8% 25.7% 72.4% 62 4 19 39 1814 13811 107 218 15.3% 0.260 62 55 12 +MOT17-10-SDP 48.9% 56.9% 42.8% 67.4% 89.5% 57 23 30 4 1010 4189 163 290 58.2% 0.205 108 60 9 +MOT17-09-DPM 35.1% 35.8% 34.4% 57.6% 59.9% 26 5 19 2 2055 2260 77 161 17.5% 0.275 49 32 7 +MOT17-09-SDP 48.5% 63.5% 39.2% 57.6% 93.2% 26 7 17 2 222 2260 46 78 52.5% 0.150 35 18 7 +MOT17-10-DPM 30.9% 39.6% 25.3% 41.7% 65.3% 57 7 30 20 2852 7479 119 299 18.6% 0.264 61 66 10 +MOT17-11-DPM 46.5% 54.9% 40.3% 53.2% 72.5% 75 10 30 35 1904 4413 52 68 32.5% 0.224 27 31 9 +MOT17-11-SDP 53.2% 62.9% 46.2% 66.5% 90.7% 75 19 39 17 646 3161 55 100 59.1% 0.149 40 28 15 +OVERALL 43.5% 56.7% 35.3% 50.8% 81.6% 1638 335 749 554 38668 165772 2264 4032 38.6% 0.174 1544 1008 359 ``` diff --git a/main.js b/main.js index fc98f1f..03817fe 100755 --- a/main.js +++ b/main.js @@ -247,6 +247,16 @@ fs.readFile(`${pathRawDetectionsInput}`, function (err, f) { } }); }); + } else { + // Compute the lengths of all trajectories + const count = MOToutput.reduce((acc, e) => { + var id = e.split(',')[1]; + return acc.set(id, (acc.get(id) || 0) + 1); + }, new Map()); + + // MOT detections have a lot of false positives, so it's better to remove + // short trajectories, which are likely due to false positives + MOToutput = MOToutput.filter(line => count.get(line.split(',')[1]) >= 10); } if (!MODE_MOTChallenge) { From 9d26c8a1f62cc80745a05b1f14d61982967e8a8b Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Thu, 24 Jun 2021 00:34:33 +0200 Subject: [PATCH 14/22] Add Hungarian algorithm for matching --- package.json | 1 + tracker.js | 268 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 158 insertions(+), 111 deletions(-) diff --git a/package.json b/package.json index ee440c2..806ae3b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "lodash.isequal": "^4.5.0", "minimist": "^1.2.0", + "munkres-js": "^1.2.2", "uuid": "^3.2.1" }, "devDependencies": { diff --git a/tracker.js b/tracker.js index 8c7f762..d51fa3c 100644 --- a/tracker.js +++ b/tracker.js @@ -3,6 +3,7 @@ var ItemTracked = itemTrackedModule.ItemTracked; var kdTree = require('./lib/kdTree-min.js').kdTree; var isEqual = require('lodash.isequal') var iouAreas = require('./utils').iouAreas +var munkres = require('munkres-js'); var DEBUG_MODE = false; @@ -39,7 +40,10 @@ const params = { distanceFunc: iouDistance, // The distance limit for matching. If values need to be excluded from // matching set their distance to something greater than the distance limit - distanceLimit: 10000 + distanceLimit: 10000, + // The algorithm used to match tracks with new detections. Can be either + // 'kdTree' or 'munkres'. + matchingAlgorithm: 'kdTree', } // A dictionary of itemTracked currently tracked @@ -84,96 +88,136 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb // Match existing Tracked items with the items detected in the new frame // For each look in the new detection to find the closest match if(detectionsOfThisFrame.length > 0) { - mapOfItemsTracked.forEach(function(itemTracked) { - - // First predict the new position of the itemTracked - var predictedPosition = itemTracked.predictNextPosition() - - // Make available for matching - itemTracked.makeAvailable(); - - // Search for a detection that matches - var treeSearchResult = treeDetectionsOfThisFrame.nearest(predictedPosition, 1, params.distanceLimit)[0]; - - // Only for debug assessments of predictions - var treeSearchResultWithoutPrediction = treeDetectionsOfThisFrame.nearest(itemTracked, 1, params.distanceLimit)[0]; - // Only if we enable the extra refinement - var treeSearchMultipleResults = treeDetectionsOfThisFrame.nearest(predictedPosition, 2, params.distanceLimit); - - // If we have found something - if(treeSearchResult) { - - // This is an extra refinement that happens in 0.001% of tracked items matching - // If IOU overlap is super similar for two potential match, add an extra check - // if(treeSearchMultipleResults.length === 2) { - - // var indexFirstChoice = 0; - // if(treeSearchMultipleResults[0][1] > treeSearchMultipleResults[1][1]) { - // indexFirstChoice = 1; - // } - - // var detectionFirstChoice = { - // bbox: treeSearchMultipleResults[indexFirstChoice][0], - // distance: treeSearchMultipleResults[indexFirstChoice][1] - // } - - // var detectionSecondChoice = { - // bbox: treeSearchMultipleResults[1 - indexFirstChoice][0], - // distance: treeSearchMultipleResults[1 - indexFirstChoice][1] - // } - - // const deltaDistance = Math.abs(detectionFirstChoice.distance - detectionSecondChoice.distance); - - // if(deltaDistance < 0.05) { - - // detectionFirstChoice.area = detectionFirstChoice.bbox.w * detectionFirstChoice.bbox.h; - // detectionSecondChoice.area = detectionSecondChoice.bbox.w * detectionSecondChoice.bbox.h; - // var itemTrackedArea = itemTracked.w * itemTracked.h; - - // var deltaAreaFirstChoice = Math.abs(detectionFirstChoice.area - itemTrackedArea) / (detectionFirstChoice.area + itemTrackedArea); - // var deltaAreaSecondChoice = Math.abs(detectionSecondChoice.area - itemTrackedArea) / (detectionSecondChoice.area + itemTrackedArea); - - // // Compare the area of each, priorize the detections that as a overal similar area - // // even if it overlaps less - // if(deltaAreaFirstChoice > deltaAreaSecondChoice) { - // if(Math.abs(deltaAreaFirstChoice - deltaAreaSecondChoice) > 0.5) { - // if(DEBUG_MODE) { - // console.log('Switch choice ! wise it seems different for frame: ' + frameNb + ' itemTracked ' + itemTracked.idDisplay) - // console.log(Math.abs(deltaAreaFirstChoice - deltaAreaSecondChoice)); - // } - // // Change tree search result: - // treeSearchResult = treeSearchMultipleResults[1 - indexFirstChoice] - // } - // } - // } - // } - - if(DEBUG_MODE) { - // Assess different results between predition or not - if(!isEqual(treeSearchResult[0], treeSearchResultWithoutPrediction && treeSearchResultWithoutPrediction[0])) { - console.log('Making the pre-prediction led to a difference result:'); - console.log('For frame ' + frameNb + ' itemNb ' + itemTracked.idDisplay) + if (params.matchingAlgorithm === 'munkres') { + var trackedItemIds = Array.from(mapOfItemsTracked.keys()); + + var costMatrix = Array.from(mapOfItemsTracked.values()). + map(itemTracked => { + var predictedPosition = itemTracked.predictNextPosition(); + return detectionsOfThisFrame.map( + detection => params.distanceFunc(predictedPosition, detection)); + }); + + mapOfItemsTracked.forEach(function(itemTracked) { + itemTracked.makeAvailable(); + }); + + munkres(costMatrix). + filter(m => costMatrix[m[0]][m[1]] <= params.distanceLimit). + forEach(m => { + var itemTracked = mapOfItemsTracked.get(trackedItemIds[m[0]]); + var updatedTrackedItemProperties = detectionsOfThisFrame[m[1]]; + matchedList[m[1]] = { idDisplay: itemTracked.idDisplay }; + itemTracked. + makeUnavailable(). + update(updatedTrackedItemProperties, frameNb); + }); + + matchedList.forEach(function(matched, index) { + if (!matched) { + if (Math.min(...costMatrix.map(m => m[index])) > params.distanceLimit) { + var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) + mapOfItemsTracked.set(newItemTracked.id, newItemTracked) + newItemTracked.makeUnavailable(); + costMatrix.push(detectionsOfThisFrame.map( + detection => params.distanceFunc(newItemTracked, detection))); } } + }); + } else if (params.matchingAlgorithm === 'kdTree') { + mapOfItemsTracked.forEach(function(itemTracked) { + + // First predict the new position of the itemTracked + var predictedPosition = itemTracked.predictNextPosition() + + // Make available for matching + itemTracked.makeAvailable(); + + // Search for a detection that matches + var treeSearchResult = treeDetectionsOfThisFrame.nearest(predictedPosition, 1, params.distanceLimit)[0]; + + // Only for debug assessments of predictions + var treeSearchResultWithoutPrediction = treeDetectionsOfThisFrame.nearest(itemTracked, 1, params.distanceLimit)[0]; + // Only if we enable the extra refinement + var treeSearchMultipleResults = treeDetectionsOfThisFrame.nearest(predictedPosition, 2, params.distanceLimit); + + // If we have found something + if(treeSearchResult) { + + // This is an extra refinement that happens in 0.001% of tracked items matching + // If IOU overlap is super similar for two potential match, add an extra check + // if(treeSearchMultipleResults.length === 2) { + + // var indexFirstChoice = 0; + // if(treeSearchMultipleResults[0][1] > treeSearchMultipleResults[1][1]) { + // indexFirstChoice = 1; + // } + + // var detectionFirstChoice = { + // bbox: treeSearchMultipleResults[indexFirstChoice][0], + // distance: treeSearchMultipleResults[indexFirstChoice][1] + // } + + // var detectionSecondChoice = { + // bbox: treeSearchMultipleResults[1 - indexFirstChoice][0], + // distance: treeSearchMultipleResults[1 - indexFirstChoice][1] + // } + + // const deltaDistance = Math.abs(detectionFirstChoice.distance - detectionSecondChoice.distance); + + // if(deltaDistance < 0.05) { + + // detectionFirstChoice.area = detectionFirstChoice.bbox.w * detectionFirstChoice.bbox.h; + // detectionSecondChoice.area = detectionSecondChoice.bbox.w * detectionSecondChoice.bbox.h; + // var itemTrackedArea = itemTracked.w * itemTracked.h; + + // var deltaAreaFirstChoice = Math.abs(detectionFirstChoice.area - itemTrackedArea) / (detectionFirstChoice.area + itemTrackedArea); + // var deltaAreaSecondChoice = Math.abs(detectionSecondChoice.area - itemTrackedArea) / (detectionSecondChoice.area + itemTrackedArea); + + // // Compare the area of each, priorize the detections that as a overal similar area + // // even if it overlaps less + // if(deltaAreaFirstChoice > deltaAreaSecondChoice) { + // if(Math.abs(deltaAreaFirstChoice - deltaAreaSecondChoice) > 0.5) { + // if(DEBUG_MODE) { + // console.log('Switch choice ! wise it seems different for frame: ' + frameNb + ' itemTracked ' + itemTracked.idDisplay) + // console.log(Math.abs(deltaAreaFirstChoice - deltaAreaSecondChoice)); + // } + // // Change tree search result: + // treeSearchResult = treeSearchMultipleResults[1 - indexFirstChoice] + // } + // } + // } + // } + + if(DEBUG_MODE) { + // Assess different results between predition or not + if(!isEqual(treeSearchResult[0], treeSearchResultWithoutPrediction && treeSearchResultWithoutPrediction[0])) { + console.log('Making the pre-prediction led to a difference result:'); + console.log('For frame ' + frameNb + ' itemNb ' + itemTracked.idDisplay) + } + } - var indexClosestNewDetectedItem = detectionsOfThisFrame.indexOf(treeSearchResult[0]); - // If this detections was not already matched to a tracked item - // (otherwise it would be matched to two tracked items...) - if(!matchedList[indexClosestNewDetectedItem]) { - matchedList[indexClosestNewDetectedItem] = { - idDisplay: itemTracked.idDisplay + var indexClosestNewDetectedItem = detectionsOfThisFrame.indexOf(treeSearchResult[0]); + // If this detections was not already matched to a tracked item + // (otherwise it would be matched to two tracked items...) + if(!matchedList[indexClosestNewDetectedItem]) { + matchedList[indexClosestNewDetectedItem] = { + idDisplay: itemTracked.idDisplay + } + // Update properties of tracked object + var updatedTrackedItemProperties = detectionsOfThisFrame[indexClosestNewDetectedItem] + mapOfItemsTracked.get(itemTracked.id) + .makeUnavailable() + .update(updatedTrackedItemProperties, frameNb) + } else { + // Means two already tracked item are concurrent to get assigned a new detections + // Rule is to priorize the oldest one to avoid id-reassignment } - // Update properties of tracked object - var updatedTrackedItemProperties = detectionsOfThisFrame[indexClosestNewDetectedItem] - mapOfItemsTracked.get(itemTracked.id) - .makeUnavailable() - .update(updatedTrackedItemProperties, frameNb) - } else { - // Means two already tracked item are concurrent to get assigned a new detections - // Rule is to priorize the oldest one to avoid id-reassignment } - } - }); + }); + } else { + throw `Unknown matching algorithm "${params.matchingAlgorithm}"`; + } } else { if(DEBUG_MODE) { console.log('[Tracker] Nothing detected for frame nº' + frameNb) @@ -184,32 +228,34 @@ exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb }); } - // Add any unmatched items as new trackedItem only if those new items are not too similar - // to existing trackedItems this avoids adding some double match of YOLO and bring down drasticly reassignments - if(mapOfItemsTracked.size > 0) { // Safety check to see if we still have object tracked (could have been deleted previously) - // Rebuild tracked item tree to take in account the new positions - treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), params.distanceFunc, ["x", "y", "w", "h"]); - // console.log(`Nb new items Unmatched : ${matchedList.filter((isMatched) => isMatched === false).length}`) - matchedList.forEach(function(matched, index) { - // Iterate through unmatched new detections - if(!matched) { - // Do not add as new tracked item if it is to similar to an existing one - var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, params.distanceLimit)[0]; - - if(!treeSearchResult) { - var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) - // Add it to the map - mapOfItemsTracked.set(newItemTracked.id, newItemTracked) - // Add it to the kd tree - treeItemsTracked.insert(newItemTracked); - // Make unvailable - newItemTracked.makeUnavailable(); - } else { - // console.log('Do not add, its overlapping an existing object') + if (params.matchingAlgorithm === 'kdTree') { + // Add any unmatched items as new trackedItem only if those new items are not too similar + // to existing trackedItems this avoids adding some double match of YOLO and bring down drasticly reassignments + if(mapOfItemsTracked.size > 0) { // Safety check to see if we still have object tracked (could have been deleted previously) + // Rebuild tracked item tree to take in account the new positions + treeItemsTracked = new kdTree(Array.from(mapOfItemsTracked.values()), params.distanceFunc, ["x", "y", "w", "h"]); + // console.log(`Nb new items Unmatched : ${matchedList.filter((isMatched) => isMatched === false).length}`) + matchedList.forEach(function(matched, index) { + // Iterate through unmatched new detections + if(!matched) { + // Do not add as new tracked item if it is to similar to an existing one + var treeSearchResult = treeItemsTracked.nearest(detectionsOfThisFrame[index], 1, params.distanceLimit)[0]; + + if(!treeSearchResult) { + var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) + // Add it to the map + mapOfItemsTracked.set(newItemTracked.id, newItemTracked) + // Add it to the kd tree + treeItemsTracked.insert(newItemTracked); + // Make unvailable + newItemTracked.makeUnavailable(); + } else { + // console.log('Do not add, its overlapping an existing object') + } } - } - }); - } + }); + } + } // Start killing the itemTracked (and predicting next position) // that are tracked but haven't been matched this frame From af0e7d03c839c41561e89d9d2d346379306b0d34 Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Thu, 24 Jun 2021 13:24:18 +0200 Subject: [PATCH 15/22] Ignore DPM detections with negative confidence --- documentation/BENCHMARK.md | 52 +++++++++++++++++++------------------- main.js | 10 +++++--- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/documentation/BENCHMARK.md b/documentation/BENCHMARK.md index 633c6d3..1f02047 100644 --- a/documentation/BENCHMARK.md +++ b/documentation/BENCHMARK.md @@ -62,9 +62,9 @@ python3 -m motmetrics.apps.eval_motchallenge . . - Result ``` - IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm -MOT17-04-DPM 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 -OVERALL 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 + IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm +MOT17-04-DPM 33.5% 53.8% 24.3% 39.0% 86.4% 83 4 45 34 2924 29004 239 393 32.4% 0.217 106 141 10 +OVERALL 33.5% 53.8% 24.3% 39.0% 86.4% 83 4 45 34 2924 29004 239 393 32.4% 0.217 106 141 10 ``` ### Run full benchmark @@ -78,27 +78,27 @@ In order to benchmark the tracker on all MOT17 training sequences, delete the di On the first run, the script will download the full MOT17 training benchmark and unpack it. Then, it runs the tracker on each sequence and outputs the evaluation metrics. ``` - IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm -MOT17-04-SDP 62.2% 74.8% 53.2% 69.0% 97.1% 83 32 39 12 982 14737 121 367 66.7% 0.152 82 46 12 -MOT17-04-DPM 29.4% 36.6% 24.5% 42.5% 63.5% 83 8 43 32 11616 27366 264 469 17.5% 0.224 110 151 12 -MOT17-05-DPM 34.3% 48.2% 26.7% 40.2% 72.8% 133 9 63 61 1040 4133 94 150 23.9% 0.257 101 27 39 -MOT17-05-FRCNN 44.8% 61.3% 35.3% 51.6% 89.6% 133 24 56 53 414 3347 63 69 44.7% 0.172 82 20 39 -MOT17-11-FRCNN 55.4% 74.2% 44.2% 55.3% 92.8% 75 15 34 26 405 4219 45 50 50.5% 0.096 35 22 12 -MOT17-05-SDP 43.1% 53.9% 35.9% 58.0% 87.0% 133 31 64 38 597 2905 84 128 48.2% 0.165 108 21 45 -MOT17-02-FRCNN 31.6% 52.8% 22.6% 34.6% 81.1% 62 6 25 31 1502 12148 93 127 26.0% 0.126 55 49 11 -MOT17-09-FRCNN 43.6% 61.2% 33.8% 53.4% 96.8% 26 6 16 4 95 2481 37 39 50.9% 0.096 27 16 6 -MOT17-10-FRCNN 40.0% 46.8% 35.0% 57.9% 77.6% 57 15 35 7 2150 5405 228 311 39.4% 0.162 147 89 16 -MOT17-04-FRCNN 49.5% 67.8% 39.0% 53.2% 92.4% 83 17 43 23 2077 22271 93 90 48.6% 0.108 42 56 5 -MOT17-13-DPM 28.8% 45.8% 21.0% 27.1% 59.2% 110 10 42 58 2172 8489 75 207 7.8% 0.282 48 42 19 -MOT17-13-SDP 60.3% 78.0% 49.1% 54.5% 86.6% 110 43 25 42 980 5294 72 199 45.5% 0.212 70 24 27 -MOT17-02-SDP 34.3% 46.8% 27.1% 44.7% 77.1% 62 9 34 19 2468 10275 176 353 30.5% 0.201 114 72 13 -MOT17-13-FRCNN 50.4% 61.1% 42.9% 55.9% 79.6% 110 35 46 29 1667 5129 200 259 39.9% 0.169 141 83 34 -MOT17-02-DPM 23.3% 44.5% 15.8% 25.7% 72.4% 62 4 19 39 1814 13811 107 218 15.3% 0.260 62 55 12 -MOT17-10-SDP 48.9% 56.9% 42.8% 67.4% 89.5% 57 23 30 4 1010 4189 163 290 58.2% 0.205 108 60 9 -MOT17-09-DPM 35.1% 35.8% 34.4% 57.6% 59.9% 26 5 19 2 2055 2260 77 161 17.5% 0.275 49 32 7 -MOT17-09-SDP 48.5% 63.5% 39.2% 57.6% 93.2% 26 7 17 2 222 2260 46 78 52.5% 0.150 35 18 7 -MOT17-10-DPM 30.9% 39.6% 25.3% 41.7% 65.3% 57 7 30 20 2852 7479 119 299 18.6% 0.264 61 66 10 -MOT17-11-DPM 46.5% 54.9% 40.3% 53.2% 72.5% 75 10 30 35 1904 4413 52 68 32.5% 0.224 27 31 9 -MOT17-11-SDP 53.2% 62.9% 46.2% 66.5% 90.7% 75 19 39 17 646 3161 55 100 59.1% 0.149 40 28 15 -OVERALL 43.5% 56.7% 35.3% 50.8% 81.6% 1638 335 749 554 38668 165772 2264 4032 38.6% 0.174 1544 1008 359 + IDF1 IDP IDR Rcll Prcn GT MT PT ML FP FN IDs FM MOTA MOTP IDt IDa IDm +MOT17-04-SDP 62.2% 74.8% 53.2% 69.0% 97.1% 83 32 39 12 982 14737 121 367 66.7% 0.152 82 46 12 +MOT17-04-DPM 33.5% 53.8% 24.3% 39.0% 86.4% 83 4 45 34 2924 29004 239 393 32.4% 0.217 106 141 10 +MOT17-05-DPM 36.1% 62.7% 25.3% 35.6% 88.1% 133 11 49 73 333 4456 60 110 29.9% 0.247 65 20 25 +MOT17-05-FRCNN 44.8% 61.3% 35.3% 51.6% 89.6% 133 24 56 53 414 3347 63 69 44.7% 0.172 82 20 39 +MOT17-11-FRCNN 55.4% 74.2% 44.2% 55.3% 92.8% 75 15 34 26 405 4219 45 50 50.5% 0.096 35 22 12 +MOT17-05-SDP 43.1% 53.9% 35.9% 58.0% 87.0% 133 31 64 38 597 2905 84 128 48.2% 0.165 108 21 45 +MOT17-02-FRCNN 31.6% 52.8% 22.6% 34.6% 81.1% 62 6 25 31 1502 12148 93 127 26.0% 0.126 55 49 11 +MOT17-09-FRCNN 43.6% 61.2% 33.8% 53.4% 96.8% 26 6 16 4 95 2481 37 39 50.9% 0.096 27 16 6 +MOT17-10-FRCNN 40.0% 46.8% 35.0% 57.9% 77.6% 57 15 35 7 2150 5405 228 311 39.4% 0.162 147 89 16 +MOT17-04-FRCNN 49.5% 67.8% 39.0% 53.2% 92.4% 83 17 43 23 2077 22271 93 90 48.6% 0.108 42 56 5 +MOT17-13-DPM 24.9% 69.5% 15.2% 19.1% 87.6% 110 8 25 77 316 9416 35 102 16.1% 0.272 25 25 15 +MOT17-13-SDP 60.3% 78.0% 49.1% 54.5% 86.6% 110 43 25 42 980 5294 72 199 45.5% 0.212 70 24 27 +MOT17-02-SDP 34.3% 46.8% 27.1% 44.7% 77.1% 62 9 34 19 2468 10275 176 353 30.5% 0.201 114 72 13 +MOT17-13-FRCNN 50.4% 61.1% 42.9% 55.9% 79.6% 110 35 46 29 1667 5129 200 259 39.9% 0.169 141 83 34 +MOT17-02-DPM 22.8% 64.0% 13.9% 18.8% 86.6% 62 3 15 44 541 15090 47 103 15.6% 0.247 23 29 5 +MOT17-10-SDP 48.9% 56.9% 42.8% 67.4% 89.5% 57 23 30 4 1010 4189 163 290 58.2% 0.205 108 60 9 +MOT17-09-DPM 42.3% 52.8% 35.3% 53.3% 79.6% 26 2 19 5 725 2489 72 164 38.3% 0.273 50 23 5 +MOT17-09-SDP 48.5% 63.5% 39.2% 57.6% 93.2% 26 7 17 2 222 2260 46 78 52.5% 0.150 35 18 7 +MOT17-10-DPM 29.4% 49.6% 20.9% 36.1% 85.9% 57 7 18 32 762 8198 77 141 29.6% 0.251 36 48 8 +MOT17-11-DPM 50.3% 72.6% 38.5% 49.7% 93.6% 75 9 25 41 323 4748 45 58 45.8% 0.219 31 26 12 +MOT17-11-SDP 53.2% 62.9% 46.2% 66.5% 90.7% 75 19 39 17 646 3161 55 100 59.1% 0.149 40 28 15 +OVERALL 44.7% 62.6% 34.7% 49.2% 88.7% 1638 326 699 613 21139 171222 2051 3531 42.3% 0.170 1422 916 331 ``` diff --git a/main.js b/main.js index 03817fe..1f12d8a 100755 --- a/main.js +++ b/main.js @@ -143,11 +143,13 @@ fs.readFile(`${pathRawDetectionsInput}`, function (err, f) { confidence: parseFloat(detectionOfThisFrameArray[6]) * 100, name: "" } - // If it's the first object for this frame, init empty array - if (!detections[detectionFrameIndex]) { - detections[detectionFrameIndex] = [] + if (detection.confidence > 0) { + // If it's the first object for this frame, init empty array + if (!detections[detectionFrameIndex]) { + detections[detectionFrameIndex] = [] + } + detections[detectionFrameIndex].push(detection); } - detections[detectionFrameIndex].push(detection); } }); } From 4c0647f38e54005c4908c74176574af377610a7b Mon Sep 17 00:00:00 2001 From: Adrian Kretz Date: Thu, 24 Jun 2021 16:56:19 +0200 Subject: [PATCH 16/22] Use box center as reference point everywhere --- ItemTracked.js | 2 +- main.js | 11 +++++++---- utils.js | 18 +++++++++--------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/ItemTracked.js b/ItemTracked.js index dea1160..c1e78b6 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -196,7 +196,7 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa } itemTracked.toMOT = function(frameIndex) { - return `${frameIndex},${this.idDisplay},${this.x},${this.y},${this.w},${this.h},${this.confidence / 100},-1,-1,-1`; + return `${frameIndex},${this.idDisplay},${this.x - this.w / 2},${this.y - this.h / 2},${this.w},${this.h},${this.confidence / 100},-1,-1,-1`; } itemTracked.toJSONGenericInfo = function() { diff --git a/main.js b/main.js index fc98f1f..2a7a938 100755 --- a/main.js +++ b/main.js @@ -135,11 +135,14 @@ fs.readFile(`${pathRawDetectionsInput}`, function (err, f) { var detectionOfThisFrameArray = line.split(","); var detectionFrameIndex = parseInt(detectionOfThisFrameArray[0], 10); if (!Number.isNaN(detectionFrameIndex)) { + var w = parseFloat(detectionOfThisFrameArray[4]); + var h = parseFloat(detectionOfThisFrameArray[5]); + var detection = { - x: parseFloat(detectionOfThisFrameArray[2]), - y: parseFloat(detectionOfThisFrameArray[3]), - w: parseFloat(detectionOfThisFrameArray[4]), - h: parseFloat(detectionOfThisFrameArray[5]), + x: parseFloat(detectionOfThisFrameArray[2]) + w / 2, + y: parseFloat(detectionOfThisFrameArray[3]) + h / 2, + w, + h, confidence: parseFloat(detectionOfThisFrameArray[6]) * 100, name: "" } diff --git a/utils.js b/utils.js index 1a5512f..30f6436 100644 --- a/utils.js +++ b/utils.js @@ -7,11 +7,11 @@ exports.isDetectionTooLarge = (detections, largestAllowed) => { } const isInsideArea = (area, point) => { - const xMin = area.x - const xMax = area.x + area.w; - const yMin = area.y - const yMax = area.y + area.h; - + const xMin = area.x - area.w / 2; + const xMax = area.x + area.w / 2; + const yMin = area.y - area.h / 2; + const yMax = area.y + area.h / 2; + if(point.x >= xMin && point.x <= xMax && point.y >= yMin && @@ -35,10 +35,10 @@ exports.ignoreObjectsNotToDetect = (detections, objectsToDetect) => { const getRectangleEdges = (item) => { return { - x0: item.x, - y0: item.y, - x1: item.x + item.w, - y1: item.y + item.h + x0: item.x - item.w / 2, + y0: item.y - item.h / 2, + x1: item.x + item.w / 2, + y1: item.y + item.h / 2, } } From aa2eb16d02402d03f8b7c99ee78eafcaf102662c Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Fri, 25 Jun 2021 11:14:47 +0200 Subject: [PATCH 17/22] Chore: Bumps version to 0.8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And adds @akretz as contributor. 🎉 Closes: - Release v0.8.1 #25 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ee440c2..d9ced83 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "node-moving-things-tracker", - "version": "0.8.0", + "version": "0.8.1", "description": "Tracker by detections in javascript for node.js / browsers", - "url": "https://github.com/tdurand/node-moving-things-tracker", + "url": "https://github.com/opendatacam/node-moving-things-tracker", "main": "main.js", "bin": { "node-moving-things-tracker": "main.js" @@ -13,7 +13,8 @@ "author": "@tdurand", "contributors": [ "Benedikt Groß (http://benedikt-gross.de/)", - "Valentin Sawadski (https://github.com/vsaw/)" + "Valentin Sawadski (https://github.com/vsaw/)", + "Adrian Kretz (https://github.com/akretz)" ], "license": "MIT", "dependencies": { From 4db25bae81e492e4c8990f62196952bfa6254e96 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Thu, 10 Feb 2022 16:57:29 +0000 Subject: [PATCH 18/22] Fixes package-lock.json after adding munkres-js Closes #30 --- package-lock.json | 1471 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1469 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ef2371..433285b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,1470 @@ { "name": "node-moving-things-tracker", - "version": "0.8.0", - "lockfileVersion": 1, + "version": "0.8.1", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "node-moving-things-tracker", + "version": "0.8.1", + "license": "MIT", + "dependencies": { + "lodash.isequal": "^4.5.0", + "minimist": "^1.2.0", + "munkres-js": "^1.2.2", + "uuid": "^3.2.1" + }, + "bin": { + "node-moving-things-tracker": "main.js" + }, + "devDependencies": { + "jasmine": "^3.6.1" + } + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jasmine": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.1.tgz", + "integrity": "sha512-Jqp8P6ZWkTVFGmJwBK46p+kJNrZCdqkQ4GL+PGuBXZwK1fM4ST9BizkYgIwCFqYYqnTizAy6+XG2Ej5dFrej9Q==", + "dev": true, + "dependencies": { + "fast-glob": "^2.2.6", + "jasmine-core": "~3.6.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.6.0.tgz", + "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/munkres-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/munkres-js/-/munkres-js-1.2.2.tgz", + "integrity": "sha1-4D2YBo1F1YexX1Y+uGDrZ6qFKLc=" + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + } + }, "dependencies": { "@mrmlnc/readdir-enhanced": { "version": "2.2.1", @@ -736,6 +2198,11 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "munkres-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/munkres-js/-/munkres-js-1.2.2.tgz", + "integrity": "sha1-4D2YBo1F1YexX1Y+uGDrZ6qFKLc=" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", From 9fabf3fd2ed504fe461872d6b3f3bdb0e98a4158 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Thu, 10 Feb 2022 17:14:31 +0000 Subject: [PATCH 19/22] Chore: Updates Node.JS LTS in GitHub Action Closes - Update Node Version in automated testing. #32 --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index be06cde..3dca212 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [10.x, 12.x, 14.x] + node-version: [12.x, 14.x, 16.x] steps: - uses: actions/checkout@v2 From 3dc1f8ec88a67949821802d0e9d3393b3e383670 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Thu, 10 Feb 2022 17:50:40 +0000 Subject: [PATCH 20/22] 0.9.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 433285b..e6a2ded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "node-moving-things-tracker", - "version": "0.8.1", + "version": "0.9.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "node-moving-things-tracker", - "version": "0.8.1", + "version": "0.9.0", "license": "MIT", "dependencies": { "lodash.isequal": "^4.5.0", diff --git a/package.json b/package.json index b71104a..9c08763 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.8.1", + "version": "0.9.0", "description": "Tracker by detections in javascript for node.js / browsers", "url": "https://github.com/opendatacam/node-moving-things-tracker", "main": "main.js", From d585bd7ac63d7d2b56d9a8a8fbbdb92a39a084e0 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Tue, 1 Mar 2022 19:20:23 +0000 Subject: [PATCH 21/22] Fix: Memory Leak in ItemTracked Closes #38 --- ItemTracked.js | 27 +++++++++++++++++--- spec/ItemTracked.spec.js | 54 +++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/ItemTracked.js b/ItemTracked.js index c1e78b6..5da4f87 100644 --- a/ItemTracked.js +++ b/ItemTracked.js @@ -12,6 +12,9 @@ var computeVelocityVector = require('./utils').computeVelocityVector // "name": "car" // } +/** The maximum length of the item history. */ +exports.ITEM_HISTORY_MAX_LENGTH = 15; + // Use a simple incremental unique id for the display var idDisplay = 0; @@ -48,6 +51,9 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa h: properties.h, confidence: properties.confidence }); + if(itemTracked.itemHistory.length >= exports.ITEM_HISTORY_MAX_LENGTH) { + itemTracked.itemHistory.shift(); + } itemTracked.velocity = { dx: 0, dy: 0 @@ -79,6 +85,9 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa h: this.h, confidence: this.confidence }); + if(itemTracked.itemHistory.length >= exports.ITEM_HISTORY_MAX_LENGTH) { + itemTracked.itemHistory.shift(); + } this.name = properties.name; if(this.nameCount[properties.name]) { this.nameCount[properties.name]++; @@ -124,6 +133,9 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa h: this.h, confidence: this.confidence }); + if(itemTracked.itemHistory.length >= exports.ITEM_HISTORY_MAX_LENGTH) { + itemTracked.itemHistory.shift(); + } this.x = this.x + this.velocity.dx this.y = this.y + this.velocity.dy } @@ -142,11 +154,18 @@ exports.ItemTracked = function(properties, frameNb, unMatchedFramesTolerance, fa } // Velocity vector based on the last 15 frames itemTracked.updateVelocityVector = function() { - var AVERAGE_NBFRAME = 15; - if(this.itemHistory.length <= AVERAGE_NBFRAME) { - return computeVelocityVector(this.itemHistory[0], this.itemHistory[this.itemHistory.length - 1], this.itemHistory.length); + if(exports.ITEM_HISTORY_MAX_LENGTH <= 2) { + return { dx: undefined, dy: undefined, } + } + + if(this.itemHistory.length <= exports.ITEM_HISTORY_MAX_LENGTH) { + const start = this.itemHistory[0]; + const end = this.itemHistory[this.itemHistory.length - 1]; + return computeVelocityVector(start, end, this.itemHistory.length); } else { - return computeVelocityVector(this.itemHistory[this.itemHistory.length - AVERAGE_NBFRAME], this.itemHistory[this.itemHistory.length - 1], AVERAGE_NBFRAME); + const start = this.itemHistory[this.itemHistory.length - exports.ITEM_HISTORY_MAX_LENGTH]; + const end = this.itemHistory[this.itemHistory.length - 1]; + return computeVelocityVector(start, end, exports.ITEM_HISTORY_MAX_LENGTH); } } diff --git a/spec/ItemTracked.spec.js b/spec/ItemTracked.spec.js index 3044bd3..3ad628a 100644 --- a/spec/ItemTracked.spec.js +++ b/spec/ItemTracked.spec.js @@ -1,30 +1,54 @@ const ItemTracked = require('../ItemTracked'); describe("ItemTracked", function () { + const properties = { + x: null, + y: null, + w: null, + h: null, + name: "dummy", + confidence: null + }; + describe("idDisplay", function () { - const properties = { - x: null, - y: null, - w: null, - h: null, - name: "dummy", - confidence: null - }; const item1 = ItemTracked.ItemTracked(properties); const item2 = ItemTracked.ItemTracked(properties); - it('starts at 0', function() { - expect(item1.idDisplay).toBe(0); + it('starts at 0', function () { + expect(item1.idDisplay).toBe(0); }); - it('icrements IDs', function() { + it('icrements IDs', function () { expect(item1.idDisplay).toBeLessThan(item2.idDisplay); }); - it('resets IDs', function() { - ItemTracked.reset(); - const item3 = ItemTracked.ItemTracked(properties); - expect(item3.idDisplay).toBe(0); + it('resets IDs', function () { + ItemTracked.reset(); + const item3 = ItemTracked.ItemTracked(properties); + expect(item3.idDisplay).toBe(0); + }); + }); + + describe('itemHistory', () => { + it('stops at max length', () => { + const item1 = ItemTracked.ItemTracked(properties); + for (var i = 0; i < ItemTracked.ITEM_HISTORY_MAX_LENGTH + 2; i++) { + item1.update(properties, i); + expect(item1.itemHistory.length).toBeLessThanOrEqual(ItemTracked.ITEM_HISTORY_MAX_LENGTH); + } + }); + + it('does not store history', () => { + const originalItemHistoryMaxLen = ItemTracked.ITEM_HISTORY_MAX_LENGTH; + ItemTracked.ITEM_HISTORY_MAX_LENGTH = 0; + const item1 = ItemTracked.ItemTracked(properties); + + for (var i = 0; i < ItemTracked.ITEM_HISTORY_MAX_LENGTH + 2; i++) { + item1.update(properties, i); + expect(item1.itemHistory.length).toBe(ItemTracked.ITEM_HISTORY_MAX_LENGTH); + } + + ItemTracked.ITEM_HISTORY_MAX_LENGTH = originalItemHistoryMaxLen; }); }); }); From 9c8db12a94fa3fdc693ec17839eae98ab83e05a5 Mon Sep 17 00:00:00 2001 From: Valentin Sawadski Date: Tue, 1 Mar 2022 19:25:17 +0000 Subject: [PATCH 22/22] 0.9.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6a2ded..4d6e45b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "node-moving-things-tracker", - "version": "0.9.0", + "version": "0.9.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "node-moving-things-tracker", - "version": "0.9.0", + "version": "0.9.1", "license": "MIT", "dependencies": { "lodash.isequal": "^4.5.0", diff --git a/package.json b/package.json index 9c08763..200740e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-moving-things-tracker", - "version": "0.9.0", + "version": "0.9.1", "description": "Tracker by detections in javascript for node.js / browsers", "url": "https://github.com/opendatacam/node-moving-things-tracker", "main": "main.js",