From 47897da6fb31426dc2cd841d8b5b91dbf31b2892 Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Thu, 18 Apr 2024 08:41:49 -0700 Subject: [PATCH] videoanalysis: improve similar character checker --- plugins/objectdetector/package-lock.json | 4 +- plugins/objectdetector/package.json | 2 +- plugins/objectdetector/src/edit-distance.ts | 98 ++++++++++++++------- 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/plugins/objectdetector/package-lock.json b/plugins/objectdetector/package-lock.json index b1b23cca7f..639e557fe4 100644 --- a/plugins/objectdetector/package-lock.json +++ b/plugins/objectdetector/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/objectdetector", - "version": "0.1.35", + "version": "0.1.36", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/objectdetector", - "version": "0.1.35", + "version": "0.1.36", "license": "Apache-2.0", "dependencies": { "@scrypted/common": "file:../../common", diff --git a/plugins/objectdetector/package.json b/plugins/objectdetector/package.json index de13240b5b..8c3a9419dc 100644 --- a/plugins/objectdetector/package.json +++ b/plugins/objectdetector/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/objectdetector", - "version": "0.1.35", + "version": "0.1.36", "description": "Scrypted Video Analysis Plugin. Installed alongside a detection service like OpenCV or TensorFlow.", "author": "Scrypted", "license": "Apache-2.0", diff --git a/plugins/objectdetector/src/edit-distance.ts b/plugins/objectdetector/src/edit-distance.ts index c050d3bc62..be9430c162 100644 --- a/plugins/objectdetector/src/edit-distance.ts +++ b/plugins/objectdetector/src/edit-distance.ts @@ -1,36 +1,68 @@ -export function levenshteinDistance(str1: string, str2: string): number { - const len1 = str1.length; - const len2 = str2.length; - - // If either string is empty, the distance is the length of the other string - if (len1 === 0) return len2; - if (len2 === 0) return len1; - - let prev: number[] = new Array(len2 + 1); - let curr: number[] = new Array(len2 + 1); - - // Initialize the first row of the matrix to be the index of the second string - for (let i = 0; i <= len2; i++) { - prev[i] = i; +const similarCharacters = [ + ['0', 'O', 'D'], + ['1', 'I'], + ['2', 'Z'], + ['4', 'A'], + ['5', 'S'], + ['8', 'B'], + ['6', 'G'], + // not sure about this one. + ['A', '4'], + ['C', 'G'], + ['E', 'F'], +]; + +const similarCharactersMap = new Map>(); +for (const similarCharacter of similarCharacters) { + for (const character of similarCharacter) { + if (!similarCharactersMap.has(character)) { + similarCharactersMap.set(character, new Set()); + } + for (const similar of similarCharacter) { + similarCharactersMap.get(character)!.add(similar); } - - for (let i = 1; i <= len1; i++) { - // Initialize the current row with the distance from the previous row's first element - curr[0] = i; - - for (let j = 1; j <= len2; j++) { - let cost = str1.charAt(i - 1) === str2.charAt(j - 1) ? 0 : 1; - - // Compute the minimum of three possible operations: insertion, deletion, or substitution - curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost); - } - - // Swap the previous and current rows for the next iteration - const temp = prev; - prev = curr; - curr = temp; + } +} + +function isSameCharacter(c1: string, c2: string) { + if (c1 === c2) + return true; + + return similarCharactersMap.get(c1)?.has(c2); +} + +export function levenshteinDistance(str1: string, str2: string): number { + const len1 = str1.length; + const len2 = str2.length; + + // If either string is empty, the distance is the length of the other string + if (len1 === 0) return len2; + if (len2 === 0) return len1; + + let prev: number[] = new Array(len2 + 1); + let curr: number[] = new Array(len2 + 1); + + // Initialize the first row of the matrix to be the index of the second string + for (let i = 0; i <= len2; i++) { + prev[i] = i; + } + + for (let i = 1; i <= len1; i++) { + // Initialize the current row with the distance from the previous row's first element + curr[0] = i; + + for (let j = 1; j <= len2; j++) { + let cost = isSameCharacter(str1.charAt(i - 1), str2.charAt(j - 1)) ? 0 : 1; + + // Compute the minimum of three possible operations: insertion, deletion, or substitution + curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost); } - - return prev[len2]; + + // Swap the previous and current rows for the next iteration + const temp = prev; + prev = curr; + curr = temp; } - \ No newline at end of file + + return prev[len2]; +}