From 578ee0d3fa0b2d26a50cde21909123064c2f682a Mon Sep 17 00:00:00 2001 From: Jim Richter Date: Wed, 10 Mar 2021 13:50:41 +0100 Subject: [PATCH] feat: add some ai stuff --- .drone.yml | 2 +- .vscode/settings.json | 3 + server/.python-version | 1 + server/requirements.txt | 3 + server/test.py | 3 + view/package-lock.json | 182 ++++++++++++++++++++++ view/package.json | 3 + view/public/worker.js | 54 ++++++- view/rollup.config.js | 123 +++++++++------ view/src/ai.ts | 36 +++++ view/src/components/Analyzer.svelte | 52 ++++--- view/src/components/Editor/Painter.svelte | 14 +- view/src/helpers/AI.ts | 20 +++ view/src/helpers/CountPixels.ts | 15 +- view/src/helpers/index.ts | 3 +- view/src/routes/list.svelte | 3 +- view/tsconfig.json | 7 +- 17 files changed, 438 insertions(+), 86 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 server/.python-version create mode 100644 server/requirements.txt create mode 100644 server/test.py create mode 100644 view/src/ai.ts create mode 100644 view/src/helpers/AI.ts mode change 100755 => 100644 view/tsconfig.json diff --git a/.drone.yml b/.drone.yml index 4199b9a..225d1bd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,5 +15,5 @@ steps: from_secret: FTP_PASSWORD commands: - pwd - - cd /drone/src/view/public + - cd view/public - lftp -e "set sftp:auto-confirm true; set ftp:ssl-force true; set xfer:timeout 10000; debug 3; open -u $FTP_USERNAME,$FTP_PASSWORD sftp://ssh.jim-fx.com:2221; mkdir -p share/karl; cd share/karl; mirror -p --scan-all-first --overwrite --verbose -R --skip-noaccess; quit;" \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e404a70 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/home/jim/.pyenv/versions/3.8.6/bin/python" +} \ No newline at end of file diff --git a/server/.python-version b/server/.python-version new file mode 100644 index 0000000..2e14a95 --- /dev/null +++ b/server/.python-version @@ -0,0 +1 @@ +3.8.6 diff --git a/server/requirements.txt b/server/requirements.txt new file mode 100644 index 0000000..c2afe08 --- /dev/null +++ b/server/requirements.txt @@ -0,0 +1,3 @@ +keras_applications>=1.0.7,<=1.0.8 +image-classifiers==1.0.0 +efficientnet==1.0.0 \ No newline at end of file diff --git a/server/test.py b/server/test.py new file mode 100644 index 0000000..c280165 --- /dev/null +++ b/server/test.py @@ -0,0 +1,3 @@ +from segmentation_models import Unet + +model = Unet('resnet34', encoder_weights='imagenet') diff --git a/view/package-lock.json b/view/package-lock.json index c5696dc..2a06d6c 100755 --- a/view/package-lock.json +++ b/view/package-lock.json @@ -8,6 +8,9 @@ "name": "svelte-app", "version": "1.0.0", "dependencies": { + "@tensorflow-models/deeplab": "^0.2.1", + "@tensorflow/tfjs-backend-webgl": "^3.3.0", + "@tensorflow/tfjs-converter": "^3.3.0", "ogl": "^0.0.65", "sirv-cli": "^1.0.0", "svelte-file-dropzone": "^0.0.15" @@ -173,6 +176,73 @@ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true }, + "node_modules/@tensorflow-models/deeplab": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@tensorflow-models/deeplab/-/deeplab-0.2.1.tgz", + "integrity": "sha512-P30Q0M7DoxU/npMlAbyFG8fVE/eGp7UordxxBHkBixa4JCOFvuug5Q7vNT28b4UIM/i85BuJOImRIETab+HYFg==", + "peerDependencies": { + "@tensorflow/tfjs-converter": "^3.0.0", + "@tensorflow/tfjs-core": "^3.0.0" + } + }, + "node_modules/@tensorflow/tfjs-backend-cpu": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.3.0.tgz", + "integrity": "sha512-DLctv+PUZni26kQW1hq8jwQQ8u+GGc/p764WQIC4/IDagGtfGAUW1mHzWcTxtni2l4re1VrwE41ogWLhv4sGHg==", + "dependencies": { + "@types/seedrandom": "2.4.27", + "seedrandom": "2.4.3" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.3.0" + } + }, + "node_modules/@tensorflow/tfjs-backend-webgl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.3.0.tgz", + "integrity": "sha512-GWCtXbrjPTyye3ooId9GlcNDwnIMskZarUpNIQ5g/zeISLfwEQoutA/UqJF+HzuEHgGMsWFkmaO3xKVT7UMpdg==", + "dependencies": { + "@tensorflow/tfjs-backend-cpu": "3.3.0", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "2.4.27", + "@types/webgl-ext": "0.0.30", + "@types/webgl2": "0.0.5", + "seedrandom": "2.4.3" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.3.0" + } + }, + "node_modules/@tensorflow/tfjs-converter": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.3.0.tgz", + "integrity": "sha512-k57wN4yelePhmO9orcT/wzGMIuyedrMpVtg0FhxpV6BQu0+TZ/ti3W4Kb97GWJsoHKXMoing9SnioKfVnBW6hw==", + "peerDependencies": { + "@tensorflow/tfjs-core": "3.3.0" + } + }, + "node_modules/@tensorflow/tfjs-core": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.3.0.tgz", + "integrity": "sha512-6G+LcCiQBl4Kza5mDbWbf8QSWBTW3l7SDjGhQzMO1ITtQatHzxkuHGHcJ4CTUJvNA0JmKf4QJWOvlFqEmxwyLQ==", + "peer": true, + "dependencies": { + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "2.4.27", + "@types/webgl-ext": "0.0.30", + "node-fetch": "~2.6.1", + "seedrandom": "2.4.3" + }, + "engines": { + "yarn": ">= 1.3.2" + } + }, "node_modules/@tsconfig/svelte": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-1.0.10.tgz", @@ -191,6 +261,11 @@ "integrity": "sha512-/Ctrftx/zp4m8JOujM5ZhwzlWLx22nbQJiVqz8/zE15gOeEW+uly3FSX4fGFpcfEvFzXcMCJwq9lGVWgyARXhg==", "dev": true }, + "node_modules/@types/offscreencanvas": { + "version": "2019.3.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz", + "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==" + }, "node_modules/@types/pug": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz", @@ -215,6 +290,21 @@ "@types/node": "*" } }, + "node_modules/@types/seedrandom": { + "version": "2.4.27", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz", + "integrity": "sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE=" + }, + "node_modules/@types/webgl-ext": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz", + "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==" + }, + "node_modules/@types/webgl2": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.5.tgz", + "integrity": "sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow==" + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -1202,6 +1292,15 @@ "integrity": "sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=", "dev": true }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "peer": true, + "engines": { + "node": "4.x || >=6.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1539,6 +1638,11 @@ } ] }, + "node_modules/seedrandom": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz", + "integrity": "sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw=" + }, "node_modules/semiver": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", @@ -2126,6 +2230,53 @@ } } }, + "@tensorflow-models/deeplab": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@tensorflow-models/deeplab/-/deeplab-0.2.1.tgz", + "integrity": "sha512-P30Q0M7DoxU/npMlAbyFG8fVE/eGp7UordxxBHkBixa4JCOFvuug5Q7vNT28b4UIM/i85BuJOImRIETab+HYFg==", + "requires": {} + }, + "@tensorflow/tfjs-backend-cpu": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.3.0.tgz", + "integrity": "sha512-DLctv+PUZni26kQW1hq8jwQQ8u+GGc/p764WQIC4/IDagGtfGAUW1mHzWcTxtni2l4re1VrwE41ogWLhv4sGHg==", + "requires": { + "@types/seedrandom": "2.4.27", + "seedrandom": "2.4.3" + } + }, + "@tensorflow/tfjs-backend-webgl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.3.0.tgz", + "integrity": "sha512-GWCtXbrjPTyye3ooId9GlcNDwnIMskZarUpNIQ5g/zeISLfwEQoutA/UqJF+HzuEHgGMsWFkmaO3xKVT7UMpdg==", + "requires": { + "@tensorflow/tfjs-backend-cpu": "3.3.0", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "2.4.27", + "@types/webgl-ext": "0.0.30", + "@types/webgl2": "0.0.5", + "seedrandom": "2.4.3" + } + }, + "@tensorflow/tfjs-converter": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.3.0.tgz", + "integrity": "sha512-k57wN4yelePhmO9orcT/wzGMIuyedrMpVtg0FhxpV6BQu0+TZ/ti3W4Kb97GWJsoHKXMoing9SnioKfVnBW6hw==", + "requires": {} + }, + "@tensorflow/tfjs-core": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.3.0.tgz", + "integrity": "sha512-6G+LcCiQBl4Kza5mDbWbf8QSWBTW3l7SDjGhQzMO1ITtQatHzxkuHGHcJ4CTUJvNA0JmKf4QJWOvlFqEmxwyLQ==", + "peer": true, + "requires": { + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "2.4.27", + "@types/webgl-ext": "0.0.30", + "node-fetch": "~2.6.1", + "seedrandom": "2.4.3" + } + }, "@tsconfig/svelte": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-1.0.10.tgz", @@ -2144,6 +2295,11 @@ "integrity": "sha512-/Ctrftx/zp4m8JOujM5ZhwzlWLx22nbQJiVqz8/zE15gOeEW+uly3FSX4fGFpcfEvFzXcMCJwq9lGVWgyARXhg==", "dev": true }, + "@types/offscreencanvas": { + "version": "2019.3.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz", + "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==" + }, "@types/pug": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz", @@ -2168,6 +2324,21 @@ "@types/node": "*" } }, + "@types/seedrandom": { + "version": "2.4.27", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz", + "integrity": "sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE=" + }, + "@types/webgl-ext": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz", + "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==" + }, + "@types/webgl2": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.5.tgz", + "integrity": "sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow==" + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -2987,6 +3158,12 @@ "integrity": "sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=", "dev": true }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "peer": true + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3249,6 +3426,11 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "seedrandom": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz", + "integrity": "sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw=" + }, "semiver": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", diff --git a/view/package.json b/view/package.json index 088ea72..21b6571 100755 --- a/view/package.json +++ b/view/package.json @@ -29,6 +29,9 @@ "typescript": "^4.0.0" }, "dependencies": { + "@tensorflow-models/deeplab": "^0.2.1", + "@tensorflow/tfjs-backend-webgl": "^3.3.0", + "@tensorflow/tfjs-converter": "^3.3.0", "ogl": "^0.0.65", "sirv-cli": "^1.0.0", "svelte-file-dropzone": "^0.0.15" diff --git a/view/public/worker.js b/view/public/worker.js index 978b19c..9e01763 100644 --- a/view/public/worker.js +++ b/view/public/worker.js @@ -3,27 +3,69 @@ self.addEventListener('message', function (e) { - const { data: { i, arr: pixels } } = e; + const { data: { i, pixels, correctDistortion = true, width, height } } = e; - let store = {}; + // This is the old method just by counting pixels + const oldStore = {}; + + //This method applies some weight to the pixels + const store = {}; + let totalPixelValue = 0; let total = pixels.length / 4; const threshold = 200; for (let i = 0; i < total; i++) { + + const r = pixels[i * 4 + 0] > threshold ? 1 : 0; const g = pixels[i * 4 + 1] > threshold ? 1 : 0; const b = pixels[i * 4 + 2] > threshold ? 1 : 0; const id = r + "-" + g + "-" + b; - store[id] = store[id] + 1 || 1; + + //Caclulate y position of pixel + const y = Math.floor(i / width); + + // KarlKilian Formel + const pixelValue = Math.cos(360 / (Math.pow(height, 2)) * Math.pow(y, 2) + (-360 / height) * y + 90); + + oldStore[id] = oldStore[id] + 1 || 1; + + if (id in store) { + store[id] += pixelValue; + } else { + store[id] = pixelValue; + } + + totalPixelValue += pixelValue; + } + const finalResult = {}; - Object.keys(store).forEach(k => { - store[k] = store[k] / total; + + // Normalize stores + Object.keys(oldStore).forEach(k => { + finalResult[k] = { + distortedValue: oldStore[k] / total + } }); + Object.keys(store).forEach(k => { + finalResult[k].value = store[k] / totalPixelValue; + }); - self.postMessage({ res: store, i }); + // Conver to array for easier + const result = Object.keys(finalResult).map(key => { + const [r, g, b] = key.split("-").map((n) => parseInt(n) * 255); + return { + id: key, + color: `rgb(${r},${g},${b})`, + value: finalResult[key].value, + distortedValue: finalResult[key].distortedValue + } + }).sort((a, b) => a.value > b.value ? -1 : 1) + + self.postMessage({ result, i }); }, false); \ No newline at end of file diff --git a/view/rollup.config.js b/view/rollup.config.js index 597d702..31b372c 100755 --- a/view/rollup.config.js +++ b/view/rollup.config.js @@ -9,57 +9,82 @@ import includePaths from 'rollup-plugin-includepaths'; import glslify from 'rollup-plugin-glslify'; const production = !process.env.ROLLUP_WATCH; -export default { - input: 'src/main.ts', - output: { - sourcemap: true, - format: 'iife', - name: 'app', - file: 'public/build/bundle.js' +export default [ + { + input: 'src/ai.ts', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/ai-worker.js' + }, + plugins: [ + resolve({ + browser: true, + dedupe: ['svelte'] + }), + commonjs(), + typescript({ + sourceMap: !production, + inlineSources: !production + }), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ] }, - plugins: [ + { + input: 'src/main.ts', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/bundle.js' + }, + plugins: [ - includePaths({ - paths: ["src"], - extensions: [".ts", ".svelte"] - }), + includePaths({ + paths: ["src"], + extensions: [".ts", ".svelte"] + }), - svelte({ - preprocess: sveltePreprocess({ sourceMap: !production }), - compilerOptions: { - // enable run-time checks when not in production - dev: !production + svelte({ + preprocess: sveltePreprocess({ sourceMap: !production }), + compilerOptions: { + // enable run-time checks when not in production + dev: !production + } + }), + // we'll extract any component CSS out into + // a separate file - better for performance + css({ output: 'bundle.css' }), + + glslify(), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte'] + }), + commonjs(), + typescript({ + sourceMap: !production, + inlineSources: !production + }), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ], + watch: { + clearScreen: false, + chokidar: { + followSymlinks: true } - }), - // we'll extract any component CSS out into - // a separate file - better for performance - css({ output: 'bundle.css' }), - - glslify(), - - // If you have external dependencies installed from - // npm, you'll most likely need these plugins. In - // some cases you'll need additional configuration - - // consult the documentation for details: - // https://github.com/rollup/plugins/tree/master/packages/commonjs - resolve({ - browser: true, - dedupe: ['svelte'] - }), - commonjs(), - typescript({ - sourceMap: !production, - inlineSources: !production - }), - - // If we're building for production (npm run build - // instead of npm run dev), minify - production && terser() - ], - watch: { - clearScreen: false, - chokidar: { - followSymlinks: true } - } -}; + }]; diff --git a/view/src/ai.ts b/view/src/ai.ts new file mode 100644 index 0000000..dd711a0 --- /dev/null +++ b/view/src/ai.ts @@ -0,0 +1,36 @@ +import '@tensorflow/tfjs-backend-webgl'; +import * as tfconv from '@tensorflow/tfjs-converter'; +import * as deeplab from '@tensorflow-models/deeplab'; + +const createModel = async () => { + + console.log("Ezzzz") + const base = 'pascal'; // set to your preferred model, out of `pascal`, + // `cityscapes` and `ade20k` + const quantizationBytes = 2; // either 1, 2 or 4 + // use the getURL utility function to get the URL to the pre-trained weights + const modelUrl = deeplab.getURL(base, quantizationBytes); + const rawModel = await tfconv.loadGraphModel(modelUrl); + const modelName = 'pascal'; // set to your preferred model, out of `pascal`, + // `cityscapes` and `ade20k` + return new deeplab.SemanticSegmentation(rawModel); +}; + +const model = createModel(); +model.then(() => console.log(`Loaded the model successfully!`)); + +self.addEventListener('message', async (e) => { + + const { pixels, width, height } = e.data; + + console.log(pixels, width, height) + + var array = new Uint8ClampedArray(pixels); + + var image = new ImageData(array, width, height); + + console.log("model", await (await model).segment(image)) + + console.log(e); + +}); \ No newline at end of file diff --git a/view/src/components/Analyzer.svelte b/view/src/components/Analyzer.svelte index f327fe9..534e3cb 100644 --- a/view/src/components/Analyzer.svelte +++ b/view/src/components/Analyzer.svelte @@ -5,7 +5,7 @@ import { quartInOut } from "svelte/easing"; - let visible = true; + let correctDistortion = true; function scaleX(node, { duration, delay }) { return { @@ -20,23 +20,18 @@ }; } - const prom = countPixels(img.overlayData) - .then((res) => { - return Object.keys(res).map((c) => { - const [r, g, b] = c.split("-").map((n) => parseInt(n) * 255); - - return { - r, - g, - b, - amount: res[c], - }; - }); - }) - .then((colors) => colors.sort((a, b) => (a.amount > b.amount ? -1 : 1))); + const prom = countPixels(img, correctDistortion); -

ANALYZER

+ {#await prom}

Loading...

@@ -44,20 +39,36 @@
{#each result as color, i}

- {Math.floor(color.amount * 1000) / 10}% + {Math.floor( + (correctDistortion ? color.value : color.distortedValue) * 1000 + ) / 10}%

{/each}
{/await} diff --git a/view/src/components/Editor/Painter.svelte b/view/src/components/Editor/Painter.svelte index e18297f..18841b6 100644 --- a/view/src/components/Editor/Painter.svelte +++ b/view/src/components/Editor/Painter.svelte @@ -45,6 +45,8 @@ let my = 0; let downX, downOffset; + let debugValue = 0; + let isStrPressed = false; let isSpacePressed = false; let lastActiveTool; @@ -152,6 +154,16 @@ isOriginal = e.target.id === "cx1"; + //Caclulate y position of pixel + const y = my / wrapperHeightRatio; + + // KarlKilian Formel + debugValue = Math.cos( + (360 / Math.pow(image.height, 2)) * Math.pow(y, 2) + + (-360 / image.height) * y + + 90 + ); + if (isDown) { if (activeTool === "pan") { // TODO fix overflowiung @@ -291,7 +303,7 @@ }%)); opacity: ${(layerOpacity / 100) * 0.5};`} /> - +

{debugValue}|{my}

diff --git a/view/src/helpers/AI.ts b/view/src/helpers/AI.ts new file mode 100644 index 0000000..9bc6e1d --- /dev/null +++ b/view/src/helpers/AI.ts @@ -0,0 +1,20 @@ +const worker = new Worker("build/ai-worker.js"); + +let i = 0; + +let cb = {}; + +worker.addEventListener("message", ev => { + if (ev.data.i in cb) { + cb[ev.data.i](ev.data.res); + } +}) + +const analyze = (img: Image) => new Promise((res, rej) => { + i++; + const _i = i; + worker.postMessage({ i: _i, pixels: img.data, width: img.width, height: img.height }); + cb[_i] = res; +}); + +export default { analyze } \ No newline at end of file diff --git a/view/src/helpers/CountPixels.ts b/view/src/helpers/CountPixels.ts index 90fc1c9..75b92b0 100644 --- a/view/src/helpers/CountPixels.ts +++ b/view/src/helpers/CountPixels.ts @@ -1,3 +1,5 @@ +import { images } from "../stores"; + const worker = new Worker("worker.js"); let i = 0; @@ -6,13 +8,20 @@ let cb = {}; worker.addEventListener("message", ev => { if (ev.data.i in cb) { - cb[ev.data.i](ev.data.res); + cb[ev.data.i](ev.data.result); } }) -export default (arr: ArrayBuffer) => new Promise((res, rej) => { +interface res { + color: string + distortedValue: number + id: string + value: number +} + +export default (img: Image, correctDistortion: boolean): Promise => new Promise((res, rej) => { i++; const _i = i; - worker.postMessage({ i: _i, arr }); + worker.postMessage({ i: _i, pixels: img.overlayData, width: img.width, height: img.height, correctDistortion }); cb[_i] = res; }); \ No newline at end of file diff --git a/view/src/helpers/index.ts b/view/src/helpers/index.ts index df9c6a5..faf7d7a 100644 --- a/view/src/helpers/index.ts +++ b/view/src/helpers/index.ts @@ -1,3 +1,4 @@ export { default as bufToImageUrl } from "./BuffToImg"; export { default as fileToImage } from "./FileToImage"; -export { default as countPixels } from "./CountPixels"; \ No newline at end of file +export { default as countPixels } from "./CountPixels"; +export { default as AI } from "./AI"; \ No newline at end of file diff --git a/view/src/routes/list.svelte b/view/src/routes/list.svelte index bc942bf..47d13ac 100644 --- a/view/src/routes/list.svelte +++ b/view/src/routes/list.svelte @@ -2,7 +2,7 @@ import { Cross } from "../icons"; import { fly, fade } from "svelte/transition"; import { images as imageData, route } from "stores"; - import { bufToImageUrl } from "helpers"; + import { bufToImageUrl, AI } from "../helpers"; import type { Writable } from "svelte/store"; import Toast from "../components/Toast"; @@ -59,6 +59,7 @@ showAnalyzerIndex = undefined; } else { showAnalyzerIndex = i; + //AI.analyze(img); } } else { showAnalyzerIndex = undefined; diff --git a/view/tsconfig.json b/view/tsconfig.json old mode 100755 new mode 100644 index ada906c..d92bf2d --- a/view/tsconfig.json +++ b/view/tsconfig.json @@ -1,9 +1,8 @@ { "extends": "@tsconfig/svelte/tsconfig.json", - - "compileOptions":{ - "baseUrl": "src", + "compilerOptions": { + "baseUrl": "src" }, - "include": ["src/**/*"], + "include": ["./src/**/*"], "exclude": ["node_modules/*", "__sapper__/*", "public/*"] } \ No newline at end of file