node-moving-things-tracker
Advanced tools
Comparing version 0.7.5 to 0.8.0
@@ -18,4 +18,4 @@ var uuidv4 = require('uuid/v4'); | ||
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 = {}; | ||
@@ -27,4 +27,5 @@ // ==== Private ===== | ||
itemTracked.delete = false; | ||
itemTracked.fastDelete = fastDelete; | ||
// How many unmatched frame should I survive? | ||
itemTracked.frameUnmatchedLeftBeforeDying = DEFAULT_UNMATCHEDFRAMES_TOLERANCE; | ||
itemTracked.frameUnmatchedLeftBeforeDying = unMatchedFramesTolerance; | ||
itemTracked.isZombie = false; | ||
@@ -103,3 +104,3 @@ itemTracked.appearFrame = frameNb; | ||
itemTracked.countDown = function(frameNb) { | ||
// Set frame disappear number | ||
// Set frame disappear number | ||
if(this.disappearFrame === null) { | ||
@@ -117,3 +118,3 @@ this.disappearFrame = frameNb; | ||
// If it was matched less than 1 time, it should die quick | ||
if(this.nbTimeMatched <= 1) { | ||
if(this.fastDelete && this.nbTimeMatched <= 1) { | ||
this.frameUnmatchedLeftBeforeDying = -1; | ||
@@ -219,1 +220,4 @@ } | ||
exports.reset = function() { | ||
idDisplay = 0; | ||
} |
{ | ||
"name": "node-moving-things-tracker", | ||
"version": "0.7.5", | ||
"version": "0.8.0", | ||
"description": "Tracker by detections in javascript for node.js / browsers", | ||
@@ -11,7 +11,8 @@ "url": "https://github.com/tdurand/node-moving-things-tracker", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "jasmine" | ||
}, | ||
"author": "@tdurand", | ||
"contributors": [ | ||
"Benedikt Groß <b-g> (http://benedikt-gross.de/)" | ||
"Benedikt Groß <b-g> (http://benedikt-gross.de/)", | ||
"Valentin Sawadski <vsaw> (https://github.com/vsaw/)" | ||
], | ||
@@ -24,3 +25,5 @@ "license": "MIT", | ||
}, | ||
"devDependencies": {} | ||
"devDependencies": { | ||
"jasmine": "^3.6.1" | ||
} | ||
} |
@@ -202,2 +202,17 @@ # node-moving-things-tracker | ||
## 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 | ||
@@ -204,0 +219,0 @@ |
109
tracker.js
@@ -1,2 +0,3 @@ | ||
var ItemTracked = require('./ItemTracked').ItemTracked; | ||
const itemTrackedModule = require('./ItemTracked'); | ||
var ItemTracked = itemTrackedModule.ItemTracked; | ||
var kdTree = require('./lib/kdTree-min.js').kdTree; | ||
@@ -8,9 +9,38 @@ var isEqual = require('lodash.isequal') | ||
// 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 | ||
// 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 = params.distanceLimit + 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 | ||
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, | ||
// The function to use to determine the distance between to detected objects | ||
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 | ||
@@ -28,26 +58,5 @@ // key: uuid | ||
// 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; | ||
// 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 - IOU_LIMIT)) { | ||
distance = KDTREESEARCH_LIMIT + 1; | ||
} | ||
return distance; | ||
} | ||
exports.computeDistance = computeDistance; | ||
exports.updateTrackedItemsWithNewFrame = function(detectionsOfThisFrame, frameNb) { | ||
@@ -57,6 +66,6 @@ | ||
// 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"]); | ||
@@ -67,3 +76,3 @@ // SCENARIO 1: itemsTracked map is empty | ||
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 | ||
@@ -86,3 +95,3 @@ mapOfItemsTracked.set(newItemTracked.id, newItemTracked) | ||
var predictedPosition = itemTracked.predictNextPosition() | ||
// Make available for matching | ||
@@ -92,8 +101,8 @@ 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); | ||
@@ -133,3 +142,3 @@ // If we have found something | ||
// // 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 | ||
@@ -189,3 +198,3 @@ // if(deltaAreaFirstChoice > deltaAreaSecondChoice) { | ||
// 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}`) | ||
@@ -195,7 +204,7 @@ matchedList.forEach(function(matched, index) { | ||
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]; | ||
// 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, DEFAULT_UNMATCHEDFRAMES_TOLERANCE) | ||
var newItemTracked = ItemTracked(detectionsOfThisFrame[index], frameNb, params.unMatchedFramesTolerance, params.fastDelete) | ||
// Add it to the map | ||
@@ -214,3 +223,3 @@ mapOfItemsTracked.set(newItemTracked.id, newItemTracked) | ||
// 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 | ||
@@ -230,3 +239,3 @@ mapOfItemsTracked.forEach(function(itemTracked) { | ||
}); | ||
} | ||
@@ -238,11 +247,9 @@ } | ||
mapOfAllItemsTracked = new Map(); | ||
itemTrackedModule.reset(); | ||
} | ||
exports.setParams = function(params) { | ||
if(params.unMatchedFramesTolerance) { | ||
DEFAULT_UNMATCHEDFRAMES_TOLERANCE = params.unMatchedFramesTolerance; | ||
} | ||
if(params.iouLimit) { | ||
IOU_LIMIT = params.iouLimit; | ||
} | ||
exports.setParams = function(newParams) { | ||
Object.keys(newParams).forEach((key) => { | ||
params[key] = newParams[key]; | ||
}); | ||
} | ||
@@ -249,0 +256,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
9359376
24
2519
2
230
0
1