10 Commits

Author SHA1 Message Date
1133676b0e Add pan and zoom
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-17 08:42:15 -07:00
8ef2ea6aa4 Fix timing of image refreshing
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-15 16:13:20 -07:00
47363b9a4c Switch image display to canvas
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-15 12:58:08 -07:00
8ba930ed2e Remove run attempt from build number
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 36s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-12 19:55:30 -07:00
d2ee45c61a Add build info to specs page
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 37s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-12 19:47:09 -07:00
e4a3d1ab46 Remove safari detection
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 37s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-12 18:56:03 -07:00
862773d622 Upgrade tensorflowjs
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 37s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-11 16:32:55 -07:00
47ec235cfa Clean up new worker configuration
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 39s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-11 11:46:37 -07:00
dcdde0289b Set worker use as configuration setting
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-11 10:55:26 -07:00
390faf0a29 Replace url parse with new url for safari
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 38s
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
2024-09-10 17:41:20 -07:00
11 changed files with 248 additions and 138 deletions

View File

@@ -13,6 +13,8 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install node modules - name: Install node modules
run: npm install run: npm install
- name: Add build number
run: sed -i 's/####/#${{ github.run_number }}/' ./src/js/store.js
- name: Build pwa - name: Build pwa
run: npm run build run: npm run build
- name: Replace previous dev pwa - name: Replace previous dev pwa

5
.gitignore vendored
View File

@@ -40,7 +40,8 @@ cordova/platforms/
cordova/plugins/ cordova/plugins/
cordova/www/ cordova/www/
# Production build # Production build
www/ www/
# VSCode settings
.vscode/settings.json

View File

@@ -47,9 +47,10 @@ The following site settings are avaible:
| name | description | values | default | | name | description | values | default |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `agreeExpire` | number of months before users are shown the site agreement dialog again<br />set to 0 to display dialog on every reload | integer >= 0 | 3 | | `agreeExpire` | number of months before users are shown the site agreement dialog again<br />set to 0 to display dialog on every reload | integer >= 0 | 3 |
| `demo` | set to **true** to enable demo mode by default | boolean | false | `demo` | set to **true** to enable demo mode by default | boolean | false |
| `regions` | array of regions names to enable | thorax, abdomen, limbs, head | [thorax, abdomen, limbs, head] | | `regions` | array of regions names to enable | thorax, abdomen, limbs, head | [thorax, abdomen, limbs, head] |
| `useExternal` | detemines the ability to use an external detection server:<br />**none** - external server cannot be configured<br />**optional** - external server can be configured in the app's settings page<br />**list** - external server can be selected in the app's settings page but only the configured server(s) may be selected<br />**required** - external server settings from conf file will be used by default and disable server options in the settings page | none, optional, list, required | **optional** | | `useExternal` | detemines the ability to use an external detection server:<br />**none** - external server cannot be configured<br />**optional** - external server can be configured in the app's settings page<br />**list** - external server can be selected in the app's settings page but only the configured server(s) may be selected<br />**required** - external server settings from conf file will be used by default and disable server options in the settings page | none, optional, list, required | **optional** |
| `disableWorkers` | force app to use a single thread for detection computations instead of multi threading web workers | boolean | **optional** |
| `external` | properties of the external server(s) ALVINN may connect to<br />This setting must be a single element array if **useExternal** is set to **required**.<br />This setting must be an array of one or more elements if **useExternal** is set to **list** | external server settings array | []| | `external` | properties of the external server(s) ALVINN may connect to<br />This setting must be a single element array if **useExternal** is set to **required**.<br />This setting must be an array of one or more elements if **useExternal** is set to **list** | external server settings array | []|
| `infoUrl` | root url for links to information about identified structures<br />Structure labels with spaces replaced by underscores will be appended to this value for full information links (*e.g.,* Abdominal_diapragm) | string | info link not shown | | `infoUrl` | root url for links to information about identified structures<br />Structure labels with spaces replaced by underscores will be appended to this value for full information links (*e.g.,* Abdominal_diapragm) | string | info link not shown |

173
package-lock.json generated
View File

@@ -1,16 +1,16 @@
{ {
"name": "alvinn", "name": "alvinn",
"version": "0.5.0-rc", "version": "0.5.0-alpha",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "alvinn", "name": "alvinn",
"version": "0.5.0-rc", "version": "0.5.0-alpha",
"hasInstallScript": true, "hasInstallScript": true,
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@tensorflow/tfjs": "^4.17.0", "@tensorflow/tfjs": "^4.21.0",
"dom7": "^4.0.6", "dom7": "^4.0.6",
"framework7": "^8.3.0", "framework7": "^8.3.0",
"framework7-icons": "^5.0.5", "framework7-icons": "^5.0.5",
@@ -3354,16 +3354,17 @@
} }
}, },
"node_modules/@tensorflow/tfjs": { "node_modules/@tensorflow/tfjs": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.21.0.tgz",
"integrity": "sha512-yXRBhpM3frlNA/YaPp6HNk9EfIi8han5RYeQA3R8OCa0Od+AfoG1PUmlxV8fE2wCorlGVyHsgpiJ6M9YZPB56w==", "integrity": "sha512-7D/+H150ptvt+POMbsME3WlIvLiuBR2rCC2Z0hOKKb/5Ygkj7xsp/K2HzOvUj0g0yjk+utkU45QEYhnhjnbHRA==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@tensorflow/tfjs-backend-cpu": "4.17.0", "@tensorflow/tfjs-backend-cpu": "4.21.0",
"@tensorflow/tfjs-backend-webgl": "4.17.0", "@tensorflow/tfjs-backend-webgl": "4.21.0",
"@tensorflow/tfjs-converter": "4.17.0", "@tensorflow/tfjs-converter": "4.21.0",
"@tensorflow/tfjs-core": "4.17.0", "@tensorflow/tfjs-core": "4.21.0",
"@tensorflow/tfjs-data": "4.17.0", "@tensorflow/tfjs-data": "4.21.0",
"@tensorflow/tfjs-layers": "4.17.0", "@tensorflow/tfjs-layers": "4.21.0",
"argparse": "^1.0.10", "argparse": "^1.0.10",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"core-js": "3.29.1", "core-js": "3.29.1",
@@ -3375,9 +3376,10 @@
} }
}, },
"node_modules/@tensorflow/tfjs-backend-cpu": { "node_modules/@tensorflow/tfjs-backend-cpu": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.21.0.tgz",
"integrity": "sha512-2VSCHnX9qhYTjw9HiVwTBSnRVlntKXeBlK7aSVsmZfHGwWE2faErTtO7bWmqNqw0U7gyznJbVAjlow/p+0RNGw==", "integrity": "sha512-yS9Oisg4L48N7ML6677ilv1eP5Jt59S74skSU1cCsM4yBAtH4DAn9b89/JtqBISh6JadanfX26b4HCWQvMvqFg==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/seedrandom": "^2.4.28", "@types/seedrandom": "^2.4.28",
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
@@ -3386,15 +3388,16 @@
"yarn": ">= 1.3.2" "yarn": ">= 1.3.2"
}, },
"peerDependencies": { "peerDependencies": {
"@tensorflow/tfjs-core": "4.17.0" "@tensorflow/tfjs-core": "4.21.0"
} }
}, },
"node_modules/@tensorflow/tfjs-backend-webgl": { "node_modules/@tensorflow/tfjs-backend-webgl": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.21.0.tgz",
"integrity": "sha512-CC5GsGECCd7eYAUaKq0XJ48FjEZdgXZWPxgUYx4djvfUx5fQPp35hCSP9w/k463jllBMbjl2tKRg8u7Ia/LYzg==", "integrity": "sha512-7k6mb7dd0uF9jI51iunF3rhEXjvR/a613kjWZ0Rj3o1COFrneyku2C7cRMZERWPhbgXZ+dF+j9MdpGIpgtShIQ==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@tensorflow/tfjs-backend-cpu": "4.17.0", "@tensorflow/tfjs-backend-cpu": "4.21.0",
"@types/offscreencanvas": "~2019.3.0", "@types/offscreencanvas": "~2019.3.0",
"@types/seedrandom": "^2.4.28", "@types/seedrandom": "^2.4.28",
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
@@ -3403,21 +3406,23 @@
"yarn": ">= 1.3.2" "yarn": ">= 1.3.2"
}, },
"peerDependencies": { "peerDependencies": {
"@tensorflow/tfjs-core": "4.17.0" "@tensorflow/tfjs-core": "4.21.0"
} }
}, },
"node_modules/@tensorflow/tfjs-converter": { "node_modules/@tensorflow/tfjs-converter": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.21.0.tgz",
"integrity": "sha512-qFxIjPfomCuTrYxsFjtKbi3QfdmTTCWo+RvqD64oCMS0sjp7sUDNhJyKDoLx6LZhXlwXpHIVDJctLMRMwet0Zw==", "integrity": "sha512-cUhU+F1lGx2qnKk/gRy8odBh0PZlFz0Dl71TG8LVnj0/g352DqiNrKXlKO/po9aWzP8x0KUGC3gNMSMJW+T0DA==",
"license": "Apache-2.0",
"peerDependencies": { "peerDependencies": {
"@tensorflow/tfjs-core": "4.17.0" "@tensorflow/tfjs-core": "4.21.0"
} }
}, },
"node_modules/@tensorflow/tfjs-core": { "node_modules/@tensorflow/tfjs-core": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.21.0.tgz",
"integrity": "sha512-v9Q5430EnRpyhWNd9LVgXadciKvxLiq+sTrLKRowh26BHyAsams4tZIgX3lFKjB7b90p+FYifVMcqLTTHgjGpQ==", "integrity": "sha512-ZbECwXps5wb9XXcGq4ZXvZDVjr5okc3I0+i/vU6bpQ+nVApyIrMiyEudP8f6vracVTvNmnlN62vUXoEsQb2F8g==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/long": "^4.0.1", "@types/long": "^4.0.1",
"@types/offscreencanvas": "~2019.7.0", "@types/offscreencanvas": "~2019.7.0",
@@ -3434,28 +3439,31 @@
"node_modules/@tensorflow/tfjs-core/node_modules/@types/offscreencanvas": { "node_modules/@tensorflow/tfjs-core/node_modules/@types/offscreencanvas": {
"version": "2019.7.3", "version": "2019.7.3",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
"integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==",
"license": "MIT"
}, },
"node_modules/@tensorflow/tfjs-data": { "node_modules/@tensorflow/tfjs-data": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.21.0.tgz",
"integrity": "sha512-aPKrDFip+gXicWOFALeNT7KKQjRXFkHd/hNe/zs4mCFcIN00hy1PkZ6xkYsgrsdLDQMBSGeS4B4ZM0k5Cs88QA==", "integrity": "sha512-LpJ/vyQMwYHkcVCqIRg7IVVw13VBY7rNAiuhmKP9S5NP/2ye4KA8BJ4XwDIDgjCVQM7glK9L8bMav++xCDf7xA==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/node-fetch": "^2.1.2", "@types/node-fetch": "^2.1.2",
"node-fetch": "~2.6.1", "node-fetch": "~2.6.1",
"string_decoder": "^1.3.0" "string_decoder": "^1.3.0"
}, },
"peerDependencies": { "peerDependencies": {
"@tensorflow/tfjs-core": "4.17.0", "@tensorflow/tfjs-core": "4.21.0",
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
} }
}, },
"node_modules/@tensorflow/tfjs-layers": { "node_modules/@tensorflow/tfjs-layers": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.21.0.tgz",
"integrity": "sha512-DEE0zRKvf3LJ0EcvG5XouJYOgFGWYAneZ0K1d23969z7LfSyqVmBdLC6BTwdLKuJk3ouUJIKXU1TcpFmjDuh7g==", "integrity": "sha512-a8KaMYlY3+llvE9079nvASKpaaf8xpCMdOjbgn+eGhdOGOcY7QuFUkd/2odvnXDG8fK/jffE1LoNOlfYoBHC4w==",
"license": "Apache-2.0 AND MIT",
"peerDependencies": { "peerDependencies": {
"@tensorflow/tfjs-core": "4.17.0" "@tensorflow/tfjs-core": "4.21.0"
} }
}, },
"node_modules/@tensorflow/tfjs/node_modules/regenerator-runtime": { "node_modules/@tensorflow/tfjs/node_modules/regenerator-runtime": {
@@ -3472,7 +3480,8 @@
"node_modules/@types/long": { "node_modules/@types/long": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
"license": "MIT"
}, },
"node_modules/@types/minimist": { "node_modules/@types/minimist": {
"version": "1.2.5", "version": "1.2.5",
@@ -3492,6 +3501,7 @@
"version": "2.6.11", "version": "2.6.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"form-data": "^4.0.0" "form-data": "^4.0.0"
@@ -3506,7 +3516,8 @@
"node_modules/@types/offscreencanvas": { "node_modules/@types/offscreencanvas": {
"version": "2019.3.0", "version": "2019.3.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz",
"integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==" "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==",
"license": "MIT"
}, },
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
"version": "1.17.1", "version": "1.17.1",
@@ -3520,7 +3531,8 @@
"node_modules/@types/seedrandom": { "node_modules/@types/seedrandom": {
"version": "2.4.34", "version": "2.4.34",
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.34.tgz", "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.34.tgz",
"integrity": "sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==" "integrity": "sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==",
"license": "MIT"
}, },
"node_modules/@types/trusted-types": { "node_modules/@types/trusted-types": {
"version": "2.0.6", "version": "2.0.6",
@@ -3646,7 +3658,8 @@
"node_modules/@webgpu/types": { "node_modules/@webgpu/types": {
"version": "0.1.38", "version": "0.1.38",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.38.tgz", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.38.tgz",
"integrity": "sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==" "integrity": "sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==",
"license": "BSD-3-Clause"
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.11.2", "version": "8.11.2",
@@ -3814,7 +3827,8 @@
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
}, },
"node_modules/at-least-node": { "node_modules/at-least-node": {
"version": "1.0.0", "version": "1.0.0",
@@ -4412,6 +4426,7 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": { "dependencies": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
}, },
@@ -4872,6 +4887,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": { "engines": {
"node": ">=0.4.0" "node": ">=0.4.0"
} }
@@ -5357,6 +5373,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
@@ -6577,7 +6594,8 @@
"node_modules/long": { "node_modules/long": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
"license": "Apache-2.0"
}, },
"node_modules/lower-case": { "node_modules/lower-case": {
"version": "2.0.2", "version": "2.0.2",
@@ -6688,6 +6706,7 @@
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
@@ -6696,6 +6715,7 @@
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
}, },
@@ -6823,6 +6843,7 @@
"version": "2.6.13", "version": "2.6.13",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz",
"integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==",
"license": "MIT",
"dependencies": { "dependencies": {
"whatwg-url": "^5.0.0" "whatwg-url": "^5.0.0"
}, },
@@ -6841,17 +6862,20 @@
"node_modules/node-fetch/node_modules/tr46": { "node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
}, },
"node_modules/node-fetch/node_modules/webidl-conversions": { "node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
}, },
"node_modules/node-fetch/node_modules/whatwg-url": { "node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": { "dependencies": {
"tr46": "~0.0.3", "tr46": "~0.0.3",
"webidl-conversions": "^3.0.0" "webidl-conversions": "^3.0.0"
@@ -8481,7 +8505,8 @@
"node_modules/seedrandom": { "node_modules/seedrandom": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==",
"license": "MIT"
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "6.3.1", "version": "6.3.1",
@@ -11858,16 +11883,16 @@
} }
}, },
"@tensorflow/tfjs": { "@tensorflow/tfjs": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.21.0.tgz",
"integrity": "sha512-yXRBhpM3frlNA/YaPp6HNk9EfIi8han5RYeQA3R8OCa0Od+AfoG1PUmlxV8fE2wCorlGVyHsgpiJ6M9YZPB56w==", "integrity": "sha512-7D/+H150ptvt+POMbsME3WlIvLiuBR2rCC2Z0hOKKb/5Ygkj7xsp/K2HzOvUj0g0yjk+utkU45QEYhnhjnbHRA==",
"requires": { "requires": {
"@tensorflow/tfjs-backend-cpu": "4.17.0", "@tensorflow/tfjs-backend-cpu": "4.21.0",
"@tensorflow/tfjs-backend-webgl": "4.17.0", "@tensorflow/tfjs-backend-webgl": "4.21.0",
"@tensorflow/tfjs-converter": "4.17.0", "@tensorflow/tfjs-converter": "4.21.0",
"@tensorflow/tfjs-core": "4.17.0", "@tensorflow/tfjs-core": "4.21.0",
"@tensorflow/tfjs-data": "4.17.0", "@tensorflow/tfjs-data": "4.21.0",
"@tensorflow/tfjs-layers": "4.17.0", "@tensorflow/tfjs-layers": "4.21.0",
"argparse": "^1.0.10", "argparse": "^1.0.10",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"core-js": "3.29.1", "core-js": "3.29.1",
@@ -11883,35 +11908,35 @@
} }
}, },
"@tensorflow/tfjs-backend-cpu": { "@tensorflow/tfjs-backend-cpu": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.21.0.tgz",
"integrity": "sha512-2VSCHnX9qhYTjw9HiVwTBSnRVlntKXeBlK7aSVsmZfHGwWE2faErTtO7bWmqNqw0U7gyznJbVAjlow/p+0RNGw==", "integrity": "sha512-yS9Oisg4L48N7ML6677ilv1eP5Jt59S74skSU1cCsM4yBAtH4DAn9b89/JtqBISh6JadanfX26b4HCWQvMvqFg==",
"requires": { "requires": {
"@types/seedrandom": "^2.4.28", "@types/seedrandom": "^2.4.28",
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
} }
}, },
"@tensorflow/tfjs-backend-webgl": { "@tensorflow/tfjs-backend-webgl": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.21.0.tgz",
"integrity": "sha512-CC5GsGECCd7eYAUaKq0XJ48FjEZdgXZWPxgUYx4djvfUx5fQPp35hCSP9w/k463jllBMbjl2tKRg8u7Ia/LYzg==", "integrity": "sha512-7k6mb7dd0uF9jI51iunF3rhEXjvR/a613kjWZ0Rj3o1COFrneyku2C7cRMZERWPhbgXZ+dF+j9MdpGIpgtShIQ==",
"requires": { "requires": {
"@tensorflow/tfjs-backend-cpu": "4.17.0", "@tensorflow/tfjs-backend-cpu": "4.21.0",
"@types/offscreencanvas": "~2019.3.0", "@types/offscreencanvas": "~2019.3.0",
"@types/seedrandom": "^2.4.28", "@types/seedrandom": "^2.4.28",
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
} }
}, },
"@tensorflow/tfjs-converter": { "@tensorflow/tfjs-converter": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.21.0.tgz",
"integrity": "sha512-qFxIjPfomCuTrYxsFjtKbi3QfdmTTCWo+RvqD64oCMS0sjp7sUDNhJyKDoLx6LZhXlwXpHIVDJctLMRMwet0Zw==", "integrity": "sha512-cUhU+F1lGx2qnKk/gRy8odBh0PZlFz0Dl71TG8LVnj0/g352DqiNrKXlKO/po9aWzP8x0KUGC3gNMSMJW+T0DA==",
"requires": {} "requires": {}
}, },
"@tensorflow/tfjs-core": { "@tensorflow/tfjs-core": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.21.0.tgz",
"integrity": "sha512-v9Q5430EnRpyhWNd9LVgXadciKvxLiq+sTrLKRowh26BHyAsams4tZIgX3lFKjB7b90p+FYifVMcqLTTHgjGpQ==", "integrity": "sha512-ZbECwXps5wb9XXcGq4ZXvZDVjr5okc3I0+i/vU6bpQ+nVApyIrMiyEudP8f6vracVTvNmnlN62vUXoEsQb2F8g==",
"requires": { "requires": {
"@types/long": "^4.0.1", "@types/long": "^4.0.1",
"@types/offscreencanvas": "~2019.7.0", "@types/offscreencanvas": "~2019.7.0",
@@ -11930,9 +11955,9 @@
} }
}, },
"@tensorflow/tfjs-data": { "@tensorflow/tfjs-data": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.21.0.tgz",
"integrity": "sha512-aPKrDFip+gXicWOFALeNT7KKQjRXFkHd/hNe/zs4mCFcIN00hy1PkZ6xkYsgrsdLDQMBSGeS4B4ZM0k5Cs88QA==", "integrity": "sha512-LpJ/vyQMwYHkcVCqIRg7IVVw13VBY7rNAiuhmKP9S5NP/2ye4KA8BJ4XwDIDgjCVQM7glK9L8bMav++xCDf7xA==",
"requires": { "requires": {
"@types/node-fetch": "^2.1.2", "@types/node-fetch": "^2.1.2",
"node-fetch": "~2.6.1", "node-fetch": "~2.6.1",
@@ -11940,9 +11965,9 @@
} }
}, },
"@tensorflow/tfjs-layers": { "@tensorflow/tfjs-layers": {
"version": "4.17.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.17.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.21.0.tgz",
"integrity": "sha512-DEE0zRKvf3LJ0EcvG5XouJYOgFGWYAneZ0K1d23969z7LfSyqVmBdLC6BTwdLKuJk3ouUJIKXU1TcpFmjDuh7g==", "integrity": "sha512-a8KaMYlY3+llvE9079nvASKpaaf8xpCMdOjbgn+eGhdOGOcY7QuFUkd/2odvnXDG8fK/jffE1LoNOlfYoBHC4w==",
"requires": {} "requires": {}
}, },
"@types/estree": { "@types/estree": {

View File

@@ -24,7 +24,7 @@
"last 5 Firefox versions" "last 5 Firefox versions"
], ],
"dependencies": { "dependencies": {
"@tensorflow/tfjs": "^4.17.0", "@tensorflow/tfjs": "^4.21.0",
"dom7": "^4.0.6", "dom7": "^4.0.6",
"framework7": "^8.3.0", "framework7": "^8.3.0",
"framework7-icons": "^5.0.5", "framework7-icons": "^5.0.5",

View File

@@ -6,6 +6,7 @@ regions:
- limbs - limbs
- head - head
useExternal: none useExternal: none
disableWorkers: false
external: external:
- name: Mserver - name: Mserver
address: "192.169.1.105" address: "192.169.1.105"

View File

@@ -79,7 +79,6 @@
.then((mod) => { return mod.text() }) .then((mod) => { return mod.text() })
this.siteConf = YAML.parse(confText) this.siteConf = YAML.parse(confText)
} }
if (window.safari !== undefined) {store().safariDetected()}
const loadSiteSettings = localStorage.getItem('siteSettings') const loadSiteSettings = localStorage.getItem('siteSettings')
if (loadSiteSettings) { if (loadSiteSettings) {
let loadedSettings = JSON.parse(loadSiteSettings) let loadedSettings = JSON.parse(loadSiteSettings)
@@ -99,6 +98,9 @@
store().set('siteDemo',this.siteConf?.demo) store().set('siteDemo',this.siteConf?.demo)
store().set('infoUrl',this.siteConf?.infoUrl) store().set('infoUrl',this.siteConf?.infoUrl)
const loadServerSettings = localStorage.getItem('serverSettings') const loadServerSettings = localStorage.getItem('serverSettings')
if (this.siteConf.disableWorkers) {
store().disableWorkers()
}
if (this.siteConf?.useExternal) { if (this.siteConf?.useExternal) {
if (!['none','list','optional','required'].includes(this.siteConf.useExternal)) { if (!['none','list','optional','required'].includes(this.siteConf.useExternal)) {
console.warn(`'${this.siteConf.useExternal}' is not a valid value for useExternal configuration: using 'optional'`) console.warn(`'${this.siteConf.useExternal}' is not a valid value for useExternal configuration: using 'optional'`)

View File

@@ -5,12 +5,13 @@ const state = reactive({
enabledRegions: ['thorax','abdomen','limbs','head'], enabledRegions: ['thorax','abdomen','limbs','head'],
regionIconSet: Math.floor(Math.random() * 3) + 1, regionIconSet: Math.floor(Math.random() * 3) + 1,
version: '0.5.0-alpha', version: '0.5.0-alpha',
build: '####',
fullscreen: false, fullscreen: false,
useExternal: 'optional', useExternal: 'optional',
workersEnabled: 'true',
siteDemo: false, siteDemo: false,
externalServerList: [], externalServerList: [],
infoUrl: false, infoUrl: false
safariBrowser: false
}) })
const set = (config, confObj) => { const set = (config, confObj) => {
@@ -22,8 +23,8 @@ const agree = () => {
state.disclaimerAgreement = true state.disclaimerAgreement = true
} }
const safariDetected = () => { const disableWorkers = () => {
state.safariBrowser = true state.workersEnabled = false
} }
const getServerList = () => { const getServerList = () => {
@@ -51,14 +52,15 @@ export default () => ({
isFullscreen: computed(() => state.fullscreen), isFullscreen: computed(() => state.fullscreen),
demoMode: computed(() => state.siteDemo), demoMode: computed(() => state.siteDemo),
externalType: computed(() => state.useExternal), externalType: computed(() => state.useExternal),
useWorkers: computed(() => state.workersEnabled),
getRegions: computed(() => state.enabledRegions), getRegions: computed(() => state.enabledRegions),
getVersion: computed(() => state.version), getVersion: computed(() => state.version),
getBuild: computed(() => state.build),
getIconSet: computed(() => state.regionIconSet), getIconSet: computed(() => state.regionIconSet),
getInfoUrl: computed(() => state.infoUrl), getInfoUrl: computed(() => state.infoUrl),
isSafari: computed(() => state.safariBrowser),
set, set,
agree, agree,
safariDetected, disableWorkers,
getServerList, getServerList,
toggleFullscreen toggleFullscreen
}) })

View File

@@ -15,7 +15,7 @@
<video id="vid-view" ref="vid_viewer" :srcObject="cameraStream" :autoPlay="true" style="width: 100%; height: 100%"></video> <video id="vid-view" ref="vid_viewer" :srcObject="cameraStream" :autoPlay="true" style="width: 100%; height: 100%"></video>
<f7-button @click="captureVidFrame()" style="position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%); z-index: 3;" fill large>Capture</f7-button> <f7-button @click="captureVidFrame()" style="position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%); z-index: 3;" fill large>Capture</f7-button>
</div> </div>
<canvas id="im-draw" ref="image_cvs" @click="structureClick" :style="`display: ${(imageLoaded || videoAvailable) ? 'block' : 'none'}; flex: 1 1 0%; max-width: 100%; max-height: 100%; min-width: 0; min-height: 0; background-size: contain; background-position: center; background-repeat: no-repeat; z-index: 2;`" /> <canvas id="im-draw" ref="image_cvs" @wheel="spinWheel($event)" @mousedown.middle="startMove($event)" @mousemove="makeMove($event)" @mouseup.middle="endMove($event)" @click="structureClick" :style="`display: ${(imageLoaded || videoAvailable) ? 'block' : 'none'}; flex: 1 1 0%; max-width: 100%; max-height: 100%; min-width: 0; min-height: 0; background-size: contain; background-position: center; background-repeat: no-repeat; z-index: 2;`" />
<f7-link v-if="getInfoUrl && (selectedChip > -1)" <f7-link v-if="getInfoUrl && (selectedChip > -1)"
:style="`left: ${infoLinkPos.x}px; top: ${infoLinkPos.y}px; transform: translate(calc(-50% - ${infoLinkPos.adj}px),calc(-50% - ${infoLinkPos.adj}px));`" :style="`left: ${infoLinkPos.x}px; top: ${infoLinkPos.y}px; transform: translate(calc(-50% - ${infoLinkPos.adj}px),calc(-50% - ${infoLinkPos.adj}px));`"
class="structure-info" class="structure-info"
@@ -70,7 +70,7 @@
<f7-button v-if="videoAvailable" @click="closeCamera()"> <f7-button v-if="videoAvailable" @click="closeCamera()">
<SvgIcon icon="no_photography"/> <SvgIcon icon="no_photography"/>
</f7-button> </f7-button>
<f7-button @click="() => showDetectSettings = !showDetectSettings" :class="(imageLoaded) ? '' : 'disabled'"> <f7-button @click="toggleSettings()" :class="(imageLoaded) ? '' : 'disabled'">
<SvgIcon icon="visibility"/> <SvgIcon icon="visibility"/>
<f7-badge v-if="numResults && (showResults.length != numResults)" color="red" style="position: absolute; right: 15%; top: 15%;">{{ showResults.length - numResults }}</f7-badge> <f7-badge v-if="numResults && (showResults.length != numResults)" color="red" style="position: absolute; right: 15%; top: 15%;">{{ showResults.length - numResults }}</f7-badge>
</f7-button> </f7-button>
@@ -160,6 +160,7 @@
classesList: [], classesList: [],
imageLoaded: false, imageLoaded: false,
imageView: new Image(), imageView: new Image(),
imCvsLocation: {},
imageLoadMode: "environment", imageLoadMode: "environment",
detecting: false, detecting: false,
detectPanel: false, detectPanel: false,
@@ -181,7 +182,10 @@
cameraStream: null, cameraStream: null,
infoLinkPos: {}, infoLinkPos: {},
detectWorker: null, detectWorker: null,
vidWorker: null vidWorker: null,
canvasMoving: false,
canvasOffset: {x: 0, y: 0},
canvasZoom: 1
} }
}, },
setup() { setup() {
@@ -205,9 +209,12 @@
this.activeRegion = 3 this.activeRegion = 3
break; break;
} }
this.modelLocation = URL.parse(`../models/${this.detectorName}${this.otherSettings.mini ? '-mini' : ''}/model.json`,import.meta.url).href let modelJ = `../models/${this.detectorName}${this.otherSettings.mini ? '-mini' : ''}/model.json`
this.miniLocation = URL.parse(`../models/${this.detectorName}-mini/model.json`,import.meta.url).href let miniJ = `../models/${this.detectorName}-mini/model.json`
fetch(URL.parse(`../models/${this.detectorName}/classes.json`,import.meta.url).href) this.modelLocation = new URL(modelJ,import.meta.url).href
this.miniLocation = new URL(miniJ,import.meta.url).href
let classesJ = `../models/${this.detectorName}/classes.json`
fetch(new URL(classesJ,import.meta.url).href)
.then((mod) => { return mod.json() }) .then((mod) => { return mod.json() })
.then((classes) => { .then((classes) => {
this.classesList = classes this.classesList = classes
@@ -217,30 +224,12 @@
if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings) if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings)
}, },
mounted () { mounted () {
this.detectWorker = new detectionWorker()
this.detectWorker.onmessage = (eMount) => {
self = this
if (eMount.data.error) {
console.log(eMount.data.message)
f7.dialog.alert(`ALVINN AI model error: ${eMount.data.message}`)
}
self.modelLoading = false
}
this.vidWorker = new detectionWorker()
this.vidWorker.onmessage = (eMount) => {
self = this
if (eMount.data.error) {
console.log(eMount.data.message)
f7.dialog.alert(`ALVINN AI nano model error: ${eMount.data.message}`)
}
}
if (this.serverSettings && this.serverSettings.use) { if (this.serverSettings && this.serverSettings.use) {
this.getRemoteLabels() this.getRemoteLabels()
this.modelLoading = false this.modelLoading = false
} else { } else {
this.modelLoading = true this.modelLoading = true
if (this.isSafari) { if (!this.useWorkers) {
this.loadModel(this.modelLocation, true).then(() => { this.loadModel(this.modelLocation, true).then(() => {
this.modelLoading = false this.modelLoading = false
}).catch((e) => { }).catch((e) => {
@@ -249,6 +238,23 @@
this.modelLoading = false this.modelLoading = false
}) })
} else { } else {
this.detectWorker = new detectionWorker()
this.detectWorker.onmessage = (eMount) => {
self = this
if (eMount.data.error) {
console.log(eMount.data.message)
f7.dialog.alert(`ALVINN AI model error: ${eMount.data.message}`)
}
self.modelLoading = false
}
this.vidWorker = new detectionWorker()
this.vidWorker.onmessage = (eMount) => {
self = this
if (eMount.data.error) {
console.log(eMount.data.message)
f7.dialog.alert(`ALVINN AI nano model error: ${eMount.data.message}`)
}
}
this.detectWorker.postMessage({call: 'loadModel', weights: this.modelLocation, preload: true}) this.detectWorker.postMessage({call: 'loadModel', weights: this.modelLocation, preload: true})
this.vidWorker.postMessage({call: 'loadModel', weights: this.miniLocation, preload: true}) this.vidWorker.postMessage({call: 'loadModel', weights: this.miniLocation, preload: true})
} }
@@ -313,30 +319,35 @@
return `--chip-media-gradient: conic-gradient(from ${270 - (confFactor * 360 / 2)}deg, hsl(${confFactor * 120}deg, 100%, 50%) ${confFactor}turn, hsl(${confFactor * 120}deg, 50%, 66%) ${confFactor}turn)` return `--chip-media-gradient: conic-gradient(from ${270 - (confFactor * 360 / 2)}deg, hsl(${confFactor * 120}deg, 100%, 50%) ${confFactor}turn, hsl(${confFactor * 120}deg, 50%, 66%) ${confFactor}turn)`
}, },
async setData () { async setData () {
this.detectWorker.onmessage = (eDetect) => { if (this.detectWorker) {
self = this this.detectWorker.onmessage = (eDetect) => {
if (eDetect.data.error) { self = this
self.detecting = false if (eDetect.data.error) {
self.resultData = {} self.detecting = false
loadFailure() self.resultData = {}
f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`) loadFailure()
} else if (eDetect.data.success == 'detection') { f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`)
self.detecting = false } else if (eDetect.data.success == 'detection') {
self.resultData = eDetect.data.detections self.detecting = false
if (self.resultData) { self.resultData = eDetect.data.detections
self.resultData.detections.map(d => {d.label = self.detectorLabels[d.label].name}) if (self.resultData) {
self.resultData.detections.map(d => {d.label = self.detectorLabels[d.label].name})
}
self.uploadDirty = true
} else if (eDetect.data.success == 'model') {
self.reloadModel = false
loadSuccess()
} }
self.uploadDirty = true f7.utils.nextFrame(() => {
} else if (eDetect.data.success == 'model') { this.selectChip("redraw")
self.reloadModel = false })
loadSuccess()
} }
} }
let loadSuccess = null let loadSuccess = null
let loadFailure = null let loadFailure = null
let modelReloading = null let modelReloading = null
if (this.isSafari && this.reloadModel) { if (!this.useWorkers && this.reloadModel) {
await this.loadModel(this.modelLocation) await this.loadModel(this.modelLocation)
this.reloadModel = false this.reloadModel = false
} else { } else {
@@ -353,12 +364,14 @@
if (this.serverSettings && this.serverSettings.use) { if (this.serverSettings && this.serverSettings.use) {
this.remoteDetect() this.remoteDetect()
} else if (!this.isSafari) { } else if (this.useWorkers) {
Promise.all([modelReloading,createImageBitmap(this.imageView)]).then(res => { Promise.all([modelReloading,createImageBitmap(this.imageView)]).then(res => {
this.detectWorker.postMessage({call: 'localDetect', image: res[1]}, [res[1]]) this.detectWorker.postMessage({call: 'localDetect', image: res[1]}, [res[1]])
}) })
} else { } else {
this.localDetect(this.imageView).then(dets => { createImageBitmap(this.imageView).then(res => {
return this.localDetect(res)
}).then(dets => {
this.detecting = false this.detecting = false
this.resultData = dets this.resultData = dets
this.uploadDirty = true this.uploadDirty = true
@@ -369,6 +382,9 @@
f7.dialog.alert(`ALVINN structure finding error: ${e.message}`) f7.dialog.alert(`ALVINN structure finding error: ${e.message}`)
}) })
} }
f7.utils.nextFrame(() => {
this.selectChip("redraw")
})
}, },
selectAll (ev) { selectAll (ev) {
if (ev.target.checked) { if (ev.target.checked) {
@@ -395,7 +411,7 @@
var vidElement = this.$refs.vid_viewer var vidElement = this.$refs.vid_viewer
vidElement.width = trackDetails.width vidElement.width = trackDetails.width
vidElement.height = trackDetails.height vidElement.height = trackDetails.height
if (this.isSafari) { if (!this.useWorkers) {
this.videoFrameDetect(vidElement) this.videoFrameDetect(vidElement)
} else { } else {
this.videoFrameDetectWorker(vidElement) this.videoFrameDetectWorker(vidElement)
@@ -422,7 +438,7 @@
alert(`Camera fail: ${message}`) alert(`Camera fail: ${message}`)
}, },
selectChip ( iChip ) { selectChip ( iChip ) {
const [imCanvas, imageCtx] = this.resetView() const [_, imageCtx] = this.resetView()
if (this.selectedChip == iChip) { if (this.selectedChip == iChip) {
this.selectedChip = -1 this.selectedChip = -1
@@ -467,9 +483,19 @@
imCanvas.width = imCanvas.clientWidth imCanvas.width = imCanvas.clientWidth
imCanvas.height = imCanvas.clientHeight imCanvas.height = imCanvas.clientHeight
imageCtx.clearRect(0,0,imCanvas.width,imCanvas.height) imageCtx.clearRect(0,0,imCanvas.width,imCanvas.height)
imageCtx.translate(this.canvasOffset.x,this.canvasOffset.y)
imageCtx.scale(this.canvasZoom,this.canvasZoom)
imageCtx.globalAlpha = 1 imageCtx.globalAlpha = 1
imageCtx.strokeStyle = 'yellow' imageCtx.strokeStyle = 'yellow'
imageCtx.lineWidth = 3 imageCtx.lineWidth = 3
if (this.imageLoaded) {
let imageLoc = this.box2cvs({top: 0,left: 0,right: 1,bottom: 1})
this.imCvsLocation.top = imageLoc[0].cvsTop
this.imCvsLocation.left = imageLoc[0].cvsLeft
this.imCvsLocation.width = imageLoc[0].cvsRight - imageLoc[0].cvsLeft
this.imCvsLocation.height = imageLoc[0].cvsBottom - imageLoc[0].cvsTop
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, this.imCvsLocation.left, this.imCvsLocation.top, this.imCvsLocation.width, this.imCvsLocation.height)
}
return [imCanvas, imageCtx] return [imCanvas, imageCtx]
}, },
getImage (searchImage) { getImage (searchImage) {
@@ -510,8 +536,18 @@
this.imageView.src = imgData this.imageView.src = imgData
return(this.imageView.decode()) return(this.imageView.decode())
}).then( () => { }).then( () => {
const [imCanvas, _] = this.resetView() this.canvasOffset = {x: 0, y: 0}
imCanvas.style['background-image'] = `url(${this.imageView.src})` this.canvasZoom = 1
const imCanvas = this.$refs.image_cvs
imCanvas.width = imCanvas.clientWidth
imCanvas.height = imCanvas.clientHeight
const imageCtx = imCanvas.getContext("2d")
let imageLoc = this.box2cvs({top: 0,left: 0,right: 1,bottom: 1})
this.imCvsLocation.top = imageLoc[0].cvsTop
this.imCvsLocation.left = imageLoc[0].cvsLeft
this.imCvsLocation.width = imageLoc[0].cvsRight - imageLoc[0].cvsLeft
this.imCvsLocation.height = imageLoc[0].cvsBottom - imageLoc[0].cvsTop
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, this.imCvsLocation.left, this.imCvsLocation.top, this.imCvsLocation.width, this.imCvsLocation.height)
f7.utils.nextFrame(() => { f7.utils.nextFrame(() => {
this.setData() this.setData()
}) })
@@ -546,7 +582,7 @@
box2cvs(boxInput) { box2cvs(boxInput) {
if (!boxInput || boxInput.length == 0) return [] if (!boxInput || boxInput.length == 0) return []
const boxList = boxInput.length ? boxInput : [boxInput] const boxList = boxInput.length ? boxInput : [boxInput]
const [imCanvas, imageCtx] = this.resetView() const imCanvas = this.$refs.image_cvs
var imgWidth var imgWidth
var imgHeight var imgHeight
const imgAspect = this.imageView.width / this.imageView.height const imgAspect = this.imageView.width / this.imageView.height
@@ -567,6 +603,40 @@
} }
}) })
return cvsCoords return cvsCoords
},
toggleSettings() {
this.showDetectSettings = !this.showDetectSettings
f7.utils.nextFrame(() => {
this.selectChip("redraw")
})
},
startMove() {
this.canvasMoving = true
},
endMove() {
this.canvasMoving = false
},
makeMove(event) {
if (this.canvasMoving) {
this.canvasOffset.x += event.movementX
this.canvasOffset.y += event.movementY
this.selectChip("redraw")
}
},
spinWheel(event) {
console.log(this.canvasOffset)
console.log({x: event.clientX, y: event.clientY})
if (event.wheelDelta > 0) {
this.canvasZoom *= 1.05
this.canvasOffset.x = (((1.05 ** -1) - 1)*event.clientX + this.canvasOffset.x)*1.05
this.canvasOffset.y = (((1.05 ** -1) - 1)*event.clientY + this.canvasOffset.y)*1.05
} else if (event.wheelDelta < 0) {
this.canvasZoom /= 1.05
this.canvasOffset.x = ((.05)*event.clientX + this.canvasOffset.x)/1.05
this.canvasOffset.y = ((.05)*event.clientY + this.canvasOffset.y)/1.05
}
console.log(this.canvasOffset)
this.selectChip("redraw")
} }
} }
} }

View File

@@ -97,8 +97,7 @@
</style> </style>
<script> <script>
import { touchstart } from 'dom7' import RegionIcon from '../components/region-icon.vue'
import RegionIcon from '../components/region-icon.vue'
import store from '../js/store' import store from '../js/store'
import { f7 } from 'framework7-vue' import { f7 } from 'framework7-vue'
@@ -113,6 +112,11 @@ import RegionIcon from '../components/region-icon.vue'
} }
}, },
setup() { setup() {
//URL TESTING CODE
//let testUrl = URL.parse(`../models/thorax/model.json`,import.meta.url).href
//console.log(testUrl)
//let testUrl2 = new URL(`../models/thorax/model.json`,import.meta.url)
//console.log(testUrl2)
return store() return store()
}, },
methods: { methods: {

View File

@@ -8,7 +8,8 @@
<f7-block-title medium>Details</f7-block-title> <f7-block-title medium>Details</f7-block-title>
<f7-list> <f7-list>
<f7-list-item title="Version" :after="alvinnVersion"></f7-list-item> <f7-list-item title="Version" :after="alvinnVersion"></f7-list-item>
<f7-list-item v-if="isSafari" title="Safari" after="Workers disabled"></f7-list-item> <f7-list-item title="Build" :after="alvinnBuild"></f7-list-item>
<f7-list-item title="Workers" :after="useWorkers ? 'Enabled' : 'Disabled'"></f7-list-item>
</f7-list> </f7-list>
<f7-block-title medium>Models</f7-block-title> <f7-block-title medium>Models</f7-block-title>
<f7-list style="width: 100%;"> <f7-list style="width: 100%;">
@@ -52,8 +53,9 @@
headneckDetails: {}, headneckDetails: {},
miniHeadneckDetails: {}, miniHeadneckDetails: {},
alvinnVersion: store().getVersion, alvinnVersion: store().getVersion,
alvinnBuild: store().getBuild,
isCordova: !!window.cordova, isCordova: !!window.cordova,
isSafari: store().isSafari, useWorkers: store().useWorkers,
otherSettings: {} otherSettings: {}
} }
}, },