From cc9597dca33a2b63319d3870d5655623d1738c8f Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Fri, 23 Apr 2021 20:04:57 +0300 Subject: [PATCH 1/9] Add correct scale for video --- front/script/algorithm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/script/algorithm.js b/front/script/algorithm.js index b142404..0ead159 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -11,8 +11,8 @@ const ctx2 = cvs2.getContext('2d'); cvs1.width = 700; cvs1.height = 700; -const videoW = 640; -const videoH = 480; +const videoW = 933; +const videoH = 700; const videoOffsetX = (cvs1.width - videoW) / 2; const videoOffsetY = (cvs1.height - videoH) / 2; From b4178fae1e60076daf970cad4a6cc36eb67723a7 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Tue, 11 May 2021 14:53:49 +0300 Subject: [PATCH 2/9] Add image to matrix convert --- front/script/algorithm.js | 43 +++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/front/script/algorithm.js b/front/script/algorithm.js index 0ead159..72e1a68 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -35,7 +35,7 @@ let img = new Image(); img.src = './assets/img/scode_example2.png'; function clearCanvas(canvas) { - const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext('2d'); ctx.fillStyle = 'white'; ctx.fillRect(0, 0, canvas.width, canvas.height); } @@ -61,18 +61,20 @@ function blackwhite(img) { } } -function checkIfScode(img){ +function checkIfScode(matrix){ const amounts = [0, 0, 0]; const blackAmounts = [0, 0, 0]; - for(let y = 0; y < img.height; y++){ - for(let x = 0; x < img.width; x++){ - const i = (y * img.width + x) * 4; - const R = img.data[i]; + const h = matrix.length; + const w = matrix[0].length; + + for(let y = 0; y < h; y++){ + for(let x = 0; x < w; x++){ + const pix = matrix[x][y]; for(let i = 0; i < 3; i++){ if(checkCircle(x, y, radiuses[i])){ amounts[i]++; - if(R === 0){ + if(pix){ blackAmounts[i]++; } } @@ -94,6 +96,24 @@ function checkIfScode(img){ return true; } +function getMatrix(img){ + const matrix = []; + const row = img.width; + const column = img.height; + for(let i = 0; i < column; i ++){ + matrix[i] = []; + for(let j = 0; j < row; j ++){ + const pixel = img.data[4 * i * row + 4 * j] > 128 ? 0 : 1; + matrix[i].push(pixel); + ctx2.beginPath(); + ctx2.fillStyle = pixel ? 'red' : 'blue'; + ctx2.fillRect(j, i, 0.8, 0.8); + ctx2.fill(); + } + } + return matrix; +} + function onLoad(){ cvs2.width = img.width; cvs2.height = img.height; @@ -106,15 +126,16 @@ function onLoad(){ img = ctx2.getImageData(0, 0, img.width, img.height); blackwhite(img); + ctx2.putImageData(img, 0, 0); + + const matrix = getMatrix(img); - if(checkIfScode(img)){ + if(checkIfScode(matrix)){ console.log('Image is scode!'); } else { console.log('Image is not scode'); } - ctx2.putImageData(img, 0, 0); - ctx2.strokeStyle = 'red'; for(let i = 0; i < 3; i++){ @@ -124,7 +145,7 @@ function onLoad(){ } } -document.getElementById("makePhoto").addEventListener("click", function() { +document.getElementById('makePhoto').addEventListener('click', function() { clearCanvas(cvs1); ctx1.drawImage(video, videoOffsetX, videoOffsetY, videoW, videoH); img = new Image(); From b7184b5f59c8ad6a30fcda4d0ff34c2e59095c11 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Tue, 11 May 2021 18:52:39 +0300 Subject: [PATCH 3/9] Add rays end recognition (Needs refactor!) --- front/script/ajax.js | 2 +- front/script/algorithm.js | 204 +++++++++++++++++++++++++++++++++++++- front/script/utils.js | 48 +++++++++ 3 files changed, 249 insertions(+), 5 deletions(-) diff --git a/front/script/ajax.js b/front/script/ajax.js index 43e754f..b374c2c 100644 --- a/front/script/ajax.js +++ b/front/script/ajax.js @@ -1,4 +1,4 @@ -const localhost = 'http://localhost:8080'; +const localhost = 'http://localhost:3000'; function getRays(link, cb) { const dataGetRays = { link }; diff --git a/front/script/algorithm.js b/front/script/algorithm.js index 72e1a68..40ad052 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -1,3 +1,5 @@ +const DIAGONAL = Math.sqrt(2); + const CIRCLE_START = 0; const CIRCLE_END = 2 * Math.PI; const PIXEL_DATA_LENGTH = 4; @@ -105,15 +107,207 @@ function getMatrix(img){ for(let j = 0; j < row; j ++){ const pixel = img.data[4 * i * row + 4 * j] > 128 ? 0 : 1; matrix[i].push(pixel); - ctx2.beginPath(); - ctx2.fillStyle = pixel ? 'red' : 'blue'; - ctx2.fillRect(j, i, 0.8, 0.8); - ctx2.fill(); } } return matrix; } +function exploreLine(matrix, startPos = new Vector2()){ + const h = matrix.length; + const w = matrix[0].length; + const openedNodes = []; + const closedNodes = []; + if(!matrix[startPos.x][startPos.y]){ + console.log('fail'); + return null; + } + const startNode = { pos: startPos, g: 0, parent: null }; + openedNodes.push(startNode); + let curr = startNode; + let counter = 0; + let thebest = curr; + while(openedNodes.length > 0 && counter < 4000){ + counter++; + if(counter === 4000) throw(new Error("too many iterations")); + let bestNode = openedNodes[0]; + for (let i = 1; i < openedNodes.length; i++){ + let nextNode = openedNodes[i]; + if (nextNode.g > bestNode.g){ + bestNode = nextNode; + } + } + if(bestNode.g > thebest.g){ + thebest = bestNode; + } + + curr = bestNode; + openedNodes.splice(openedNodes.indexOf(curr), 1); + closedNodes.push(curr); + for(let i = -1; i <= 1; i++){ + for(let j = -1; j <= 1; j++){ + if((i !== 0 || j !== 0)){ + const x = curr.pos.x + i; + const y = curr.pos.y + j; + if(x < 0 || y < 0 || x >= w || y >= h) continue; + if(!matrix[x][y]) continue; + let b = false; + for (const node of closedNodes){ + if (node.pos.x === curr.pos.x + i && node.pos.y === curr.pos.y + j) { + b = true; + break; + } + } + const newG = curr.g + (Math.abs(i) + Math.abs(j) === 1 ? 1 : DIAGONAL); + + if (!b){ + const neighbour = { pos: curr.pos.add(new Vector2(i, j)), g: newG , parent: curr }; + + let c = false; + for (const node of openedNodes){ + if (Vector2.equals(node.pos, neighbour.pos)){ + c = true; + } + } + if(!c || newG < neighbour.g){ + neighbour.g = newG; + if(!c) openedNodes.push(neighbour); + } + } + } + } + } + if (openedNodes.length === 0){ + const res = []; + let parent = thebest; + while (parent.parent) { + parent = parent.parent; + if(!parent.parent) res.push(parent.pos); + } + res.push(thebest.pos); + // for (const node of closedNodes){ + // ctx2.beginPath(); + // ctx2.fillStyle = 'red'; + // ctx2.fillRect(node.pos.y, node.pos.x, 0.8, 0.8); + // ctx2.fill(); + // } + return res; + } + } +} + +function getLine(matrix, startPos){ + const line = exploreLine(matrix, startPos); + const endPos = line[1]; + const line2 = exploreLine(matrix, endPos); + + const a = line2[0]; + const b = line2[1]; + + ctx2.strokeStyle = 'green'; + ctx2.lineWidth = 4; + + ctx2.beginPath(); + ctx2.moveTo(a.y, a.x); + ctx2.lineTo(b.y, b.x); + ctx2.stroke(); + + ctx2.strokeStyle = 'red'; + ctx2.lineWidth = 2; + + ctx2.beginPath(); + ctx2.arc(a.y, a.x, 3, CIRCLE_START, CIRCLE_END); + ctx2.stroke(); + + ctx2.beginPath(); + ctx2.arc(b.y, b.x, 3, CIRCLE_START, CIRCLE_END); + ctx2.stroke(); + + return line2; +} + +function findlines(matrix){ + const lines = []; + const h = matrix.length; + const w = matrix[0].length; + let cntr = 0; + for(let i = 0; i < h; i++){ + for(let j = 0; j < w; j++){ + if(!matrix[i][j]) continue; + // if(cntr > 3342) { + // const a = lines[lines.length - 1][0]; + // ctx2.strokeStyle = 'green'; + // ctx2.lineWidth = 4; + + // ctx2.beginPath(); + // ctx2.arc(a.y, a.x, 5, CIRCLE_START, CIRCLE_END); + // ctx2.stroke(); + + // const b = lines[lines.length - 1][1]; + // ctx2.strokeStyle = 'blue'; + // ctx2.lineWidth = 4; + + // ctx2.beginPath(); + // ctx2.arc(b.y, b.x, 5, CIRCLE_START, CIRCLE_END); + // ctx2.stroke(); + + // console.log(lines.length); + // return; + // }; + cntr++; + let bool = false; + for(const line of lines){ + const V2 = line[1].subtract(line[0]); + const V = V2.rotate(Math.PI / 2); + // const a = line[0]; + // const b = line[0].add(V); + + // ctx2.strokeStyle = 'red'; + // ctx2.lineWidth = 4; + + // ctx2.beginPath(); + // ctx2.moveTo(a.y, a.x); + // ctx2.lineTo(b.y, b.x); + // ctx2.stroke(); + // console.log(V); + + const A = V.x; + const B = V.y; + const C = - A * line[0].x - B * line[0].y; + const dist = Math.abs(A * i + B * j + C) / Math.sqrt(A * A + B * B); + + const mid = line[0].add(line[1]).divide(2); + const A2 = V2.x; + const B2 = V2.y; + const C2 = - A2 * mid.x - B2 * mid.y; + const dist2 = Math.abs(A2 * i + B2 * j + C2) / Math.sqrt(A2 * A2 + B2 * B2); + + // const a = mid; + // const b = mid.add(V); + + // ctx2.strokeStyle = 'red'; + // ctx2.lineWidth = 4; + + // ctx2.beginPath(); + // ctx2.moveTo(a.y, a.x); + // ctx2.lineTo(b.y, b.x); + // ctx2.stroke(); + const border = 3; + const len = V2.length() / 2; + if(dist < 3 && dist2 <= len + 3){ + bool = true; + break; + } + } + + if(bool) continue; + + const line = getLine(matrix, new Vector2(i, j)); + lines.push(line); + } + } + console.log(lines.length); +} + function onLoad(){ cvs2.width = img.width; cvs2.height = img.height; @@ -136,6 +330,8 @@ function onLoad(){ console.log('Image is not scode'); } + findlines(matrix); + ctx2.strokeStyle = 'red'; for(let i = 0; i < 3; i++){ diff --git a/front/script/utils.js b/front/script/utils.js index 82479b5..060b3c5 100644 --- a/front/script/utils.js +++ b/front/script/utils.js @@ -5,3 +5,51 @@ function drawline(ctx, a, b){ ctx.lineTo(b.x, b.y); ctx.stroke(); } + +class Vector2 { + constructor(_x = 0, _y = 0) { + this.x = _x; + this.y = _y; + } + + static middle = new Vector2(400, 400); + + static Zero = new Vector2(0, 0); + + static getAngle = (vector) => Math.acos(vector.x / vector.length()) * Math.sign(vector.y); + + static makeFromAngle = (magnitude, _angle) => { + return new Vector2(Math.cos(_angle) * magnitude, Math.sin(_angle) * magnitude); + } + + static equals (vector1, vector2){ + return vector1.x === vector2.x && vector1.y === vector2.y; + } + + length = () => Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); + normalized = () =>{ + return new Vector2(this.x / this.length(), this.y / this.length()) + } + add = (_vector) => { + return new Vector2(this.x + _vector.x, this.y + _vector.y) + } + subtract = (_vector) => { + return new Vector2(this.x - _vector.x, this.y - _vector.y) + } + reversed = () => { + return new Vector2(-this.x, -this.y) + } + + rotate = (_angle) => { + return Vector2.makeFromAngle(this.length(), Vector2.getAngle(this) + _angle); + } + + multiply = (n) => new Vector2(this.x * n, this.y * n); + + divide = (n) => new Vector2(this.x / n, this.y / n); + + ToString = () => { + return '{ ' + Math.round(this.x) + ', ' + Math.round(this.y) + ' }'; + } + +} From a9894b97818df562fa429d83a64a23f706a3edfb Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 12:13:13 +0300 Subject: [PATCH 4/9] Some refactor --- front/script/ajax.js | 2 +- front/script/algorithm.js | 205 +++++++++++++++----------------------- front/script/utils.js | 14 ++- 3 files changed, 88 insertions(+), 133 deletions(-) diff --git a/front/script/ajax.js b/front/script/ajax.js index b374c2c..43e754f 100644 --- a/front/script/ajax.js +++ b/front/script/ajax.js @@ -1,4 +1,4 @@ -const localhost = 'http://localhost:3000'; +const localhost = 'http://localhost:8080'; function getRays(link, cb) { const dataGetRays = { link }; diff --git a/front/script/algorithm.js b/front/script/algorithm.js index 40ad052..328972d 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -1,10 +1,12 @@ const DIAGONAL = Math.sqrt(2); -const CIRCLE_START = 0; -const CIRCLE_END = 2 * Math.PI; -const PIXEL_DATA_LENGTH = 4; +const MAX_PATH_ITERATIONS = 4000; + +const PIX_DATA_LEN = 4; const BLACKWHITE_THRESHOLD = 80; +const BLACKWHITE_MID_THRESHOLD = 128; + const cvs1 = document.getElementById('canvas1'); const cvs2 = document.getElementById('canvas2'); @@ -49,7 +51,7 @@ const checkCircle = (x, y, radius) => Math.abs(Math.sqrt(square(x - imageMid.x) function blackwhite(img) { const picLength = img.width * img.height; - for (let i = 0; i < picLength * PIXEL_DATA_LENGTH; i += PIXEL_DATA_LENGTH) { + for (let i = 0; i < picLength * PIX_DATA_LEN; i += PIX_DATA_LEN) { const R = img.data[i]; const G = img.data[i + 1]; const B = img.data[i + 2]; @@ -102,11 +104,12 @@ function getMatrix(img){ const matrix = []; const row = img.width; const column = img.height; - for(let i = 0; i < column; i ++){ - matrix[i] = []; - for(let j = 0; j < row; j ++){ - const pixel = img.data[4 * i * row + 4 * j] > 128 ? 0 : 1; - matrix[i].push(pixel); + for(let j = 0; j < column; j ++){ + matrix[j] = []; + for(let i = 0; i < row; i++){ + const ind = PIX_DATA_LEN * j * row + PIX_DATA_LEN * i; + const pixel = img.data[ind] >= BLACKWHITE_MID_THRESHOLD ? 0 : 1; + matrix[j].push(pixel); } } return matrix; @@ -117,79 +120,73 @@ function exploreLine(matrix, startPos = new Vector2()){ const w = matrix[0].length; const openedNodes = []; const closedNodes = []; - if(!matrix[startPos.x][startPos.y]){ + if(!matrix[startPos.y][startPos.x]){ console.log('fail'); return null; } - const startNode = { pos: startPos, g: 0, parent: null }; + const startNode = { pos: startPos, dist: 0, parent: null }; openedNodes.push(startNode); let curr = startNode; let counter = 0; - let thebest = curr; - while(openedNodes.length > 0 && counter < 4000){ + let bestNode = curr; + while(openedNodes.length > 0 && counter < MAX_PATH_ITERATIONS){ counter++; - if(counter === 4000) throw(new Error("too many iterations")); - let bestNode = openedNodes[0]; + if(counter === MAX_PATH_ITERATIONS) throw(new Error('too many iterations')); + let bestOpenNode = openedNodes[0]; for (let i = 1; i < openedNodes.length; i++){ let nextNode = openedNodes[i]; - if (nextNode.g > bestNode.g){ - bestNode = nextNode; + if (nextNode.dist > bestOpenNode.dist){ + bestOpenNode = nextNode; } } - if(bestNode.g > thebest.g){ - thebest = bestNode; + if(bestOpenNode.dist > bestNode.dist){ + bestNode = bestOpenNode; } - curr = bestNode; + curr = bestOpenNode; openedNodes.splice(openedNodes.indexOf(curr), 1); closedNodes.push(curr); - for(let i = -1; i <= 1; i++){ - for(let j = -1; j <= 1; j++){ + for(let j = -1; j <= 1; j++){ + for(let i = -1; i <= 1; i++){ if((i !== 0 || j !== 0)){ const x = curr.pos.x + i; const y = curr.pos.y + j; if(x < 0 || y < 0 || x >= w || y >= h) continue; - if(!matrix[x][y]) continue; - let b = false; + if(!matrix[y][x]) continue; + let nodeClosed = false; for (const node of closedNodes){ if (node.pos.x === curr.pos.x + i && node.pos.y === curr.pos.y + j) { - b = true; + nodeClosed = true; break; } } - const newG = curr.g + (Math.abs(i) + Math.abs(j) === 1 ? 1 : DIAGONAL); + const newG = curr.dist + (Math.abs(i) + Math.abs(j) === 1 ? 1 : DIAGONAL); - if (!b){ - const neighbour = { pos: curr.pos.add(new Vector2(i, j)), g: newG , parent: curr }; + if (!nodeClosed){ + const neighbour = { pos: curr.pos.add(new Vector2(i, j)), dist: newG , parent: curr }; - let c = false; + let nodeOpened = false; for (const node of openedNodes){ if (Vector2.equals(node.pos, neighbour.pos)){ - c = true; + nodeOpened = true; } } - if(!c || newG < neighbour.g){ - neighbour.g = newG; - if(!c) openedNodes.push(neighbour); + if(!nodeOpened || newG < neighbour.dist){ + neighbour.dist = newG; + if(!nodeOpened) openedNodes.push(neighbour); } } } } } if (openedNodes.length === 0){ - const res = []; - let parent = thebest; + const res = Object.create(null); + let parent = bestNode; while (parent.parent) { parent = parent.parent; - if(!parent.parent) res.push(parent.pos); + if(!parent.parent) res.start = parent.pos; } - res.push(thebest.pos); - // for (const node of closedNodes){ - // ctx2.beginPath(); - // ctx2.fillStyle = 'red'; - // ctx2.fillRect(node.pos.y, node.pos.x, 0.8, 0.8); - // ctx2.fill(); - // } + res.end = bestNode.pos; return res; } } @@ -197,115 +194,71 @@ function exploreLine(matrix, startPos = new Vector2()){ function getLine(matrix, startPos){ const line = exploreLine(matrix, startPos); - const endPos = line[1]; + const endPos = line.end; const line2 = exploreLine(matrix, endPos); - const a = line2[0]; - const b = line2[1]; - ctx2.strokeStyle = 'green'; ctx2.lineWidth = 4; - ctx2.beginPath(); - ctx2.moveTo(a.y, a.x); - ctx2.lineTo(b.y, b.x); - ctx2.stroke(); + drawline(ctx2, line2.start, line2.end); ctx2.strokeStyle = 'red'; ctx2.lineWidth = 2; - ctx2.beginPath(); - ctx2.arc(a.y, a.x, 3, CIRCLE_START, CIRCLE_END); - ctx2.stroke(); - - ctx2.beginPath(); - ctx2.arc(b.y, b.x, 3, CIRCLE_START, CIRCLE_END); - ctx2.stroke(); + drawCircle(ctx2, line2.start); + drawCircle(ctx2, line2.end); return line2; } +function findDistanceToLine(point, linePos, lineNormVector){ + + const A = lineNormVector.x; + const B = lineNormVector.y; + const C = - A * linePos.x - B * linePos.y; + + return Math.abs(A * point.x + B * point.y + C) / Math.sqrt(A * A + B * B); +} + function findlines(matrix){ const lines = []; const h = matrix.length; const w = matrix[0].length; - let cntr = 0; - for(let i = 0; i < h; i++){ - for(let j = 0; j < w; j++){ - if(!matrix[i][j]) continue; - // if(cntr > 3342) { - // const a = lines[lines.length - 1][0]; - // ctx2.strokeStyle = 'green'; - // ctx2.lineWidth = 4; - - // ctx2.beginPath(); - // ctx2.arc(a.y, a.x, 5, CIRCLE_START, CIRCLE_END); - // ctx2.stroke(); - - // const b = lines[lines.length - 1][1]; - // ctx2.strokeStyle = 'blue'; - // ctx2.lineWidth = 4; - - // ctx2.beginPath(); - // ctx2.arc(b.y, b.x, 5, CIRCLE_START, CIRCLE_END); - // ctx2.stroke(); - - // console.log(lines.length); - // return; - // }; - cntr++; - let bool = false; + + for(let j = 0; j < h; j++){ + for(let i = 0; i < w; i++){ + if(!matrix[j][i]) continue; + + let lineExists = false; + for(const line of lines){ - const V2 = line[1].subtract(line[0]); - const V = V2.rotate(Math.PI / 2); - // const a = line[0]; - // const b = line[0].add(V); - - // ctx2.strokeStyle = 'red'; - // ctx2.lineWidth = 4; - - // ctx2.beginPath(); - // ctx2.moveTo(a.y, a.x); - // ctx2.lineTo(b.y, b.x); - // ctx2.stroke(); - // console.log(V); - - const A = V.x; - const B = V.y; - const C = - A * line[0].x - B * line[0].y; - const dist = Math.abs(A * i + B * j + C) / Math.sqrt(A * A + B * B); - - const mid = line[0].add(line[1]).divide(2); - const A2 = V2.x; - const B2 = V2.y; - const C2 = - A2 * mid.x - B2 * mid.y; - const dist2 = Math.abs(A2 * i + B2 * j + C2) / Math.sqrt(A2 * A2 + B2 * B2); - - // const a = mid; - // const b = mid.add(V); - - // ctx2.strokeStyle = 'red'; - // ctx2.lineWidth = 4; - - // ctx2.beginPath(); - // ctx2.moveTo(a.y, a.x); - // ctx2.lineTo(b.y, b.x); - // ctx2.stroke(); + + const v = line.end.subtract(line.start); + const n = v.rotate(Math.PI / 2); + + const point = new Vector2(i, j); + + const dist = findDistanceToLine(point, line.start, n); + + const mid = line.start.add(line.end).divide(2); + + const dist2 = findDistanceToLine(point, mid, v); + const border = 3; - const len = V2.length() / 2; - if(dist < 3 && dist2 <= len + 3){ - bool = true; + const len = v.length() / 2; + if(dist < border && dist2 <= len + border){ + lineExists = true; break; } } - if(bool) continue; + if(lineExists) continue; const line = getLine(matrix, new Vector2(i, j)); lines.push(line); } } - console.log(lines.length); + console.log('Found lines: ' + lines.length); } function onLoad(){ @@ -335,9 +288,7 @@ function onLoad(){ ctx2.strokeStyle = 'red'; for(let i = 0; i < 3; i++){ - ctx2.beginPath(); - ctx2.arc(imageMid.x, imageMid.y, radiuses[i], CIRCLE_START, CIRCLE_END); - ctx2.stroke(); + drawCircle(ctx2, imageMid, radiuses[i]); } } diff --git a/front/script/utils.js b/front/script/utils.js index 060b3c5..570296f 100644 --- a/front/script/utils.js +++ b/front/script/utils.js @@ -1,3 +1,5 @@ +const CIRCLE_START = 0; +const CIRCLE_END = 2 * Math.PI; function drawline(ctx, a, b){ ctx.beginPath(); @@ -6,16 +8,18 @@ function drawline(ctx, a, b){ ctx.stroke(); } +function drawCircle(ctx, pos, radius = 3){ + ctx.beginPath(); + ctx.arc(pos.x, pos.y, radius, CIRCLE_START, CIRCLE_END); + ctx.stroke(); +} + class Vector2 { constructor(_x = 0, _y = 0) { this.x = _x; this.y = _y; } - static middle = new Vector2(400, 400); - - static Zero = new Vector2(0, 0); - static getAngle = (vector) => Math.acos(vector.x / vector.length()) * Math.sign(vector.y); static makeFromAngle = (magnitude, _angle) => { @@ -36,7 +40,7 @@ class Vector2 { subtract = (_vector) => { return new Vector2(this.x - _vector.x, this.y - _vector.y) } - reversed = () => { + neg = () => { return new Vector2(-this.x, -this.y) } From d5e5d0b3842e6e3b65c4d5718a87c920f1751447 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 14:53:42 +0300 Subject: [PATCH 5/9] Add line lengths recognition --- front/script/ajax.js | 2 +- front/script/algorithm.js | 67 +++++++++++++++++++++++++++++++++++++-- front/script/script.js | 1 + 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/front/script/ajax.js b/front/script/ajax.js index 43e754f..b374c2c 100644 --- a/front/script/ajax.js +++ b/front/script/ajax.js @@ -1,4 +1,4 @@ -const localhost = 'http://localhost:8080'; +const localhost = 'http://localhost:3000'; function getRays(link, cb) { const dataGetRays = { link }; diff --git a/front/script/algorithm.js b/front/script/algorithm.js index 328972d..cf8009d 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -7,6 +7,7 @@ const PIX_DATA_LEN = 4; const BLACKWHITE_THRESHOLD = 80; const BLACKWHITE_MID_THRESHOLD = 128; +const MIN_LINE_LEN = 40; const cvs1 = document.getElementById('canvas1'); const cvs2 = document.getElementById('canvas2'); @@ -27,7 +28,7 @@ let correctPercentage = [ {min: 0, max: 0} ]; -let imageMid = {x: 350, y: 350} +let imageMid = new Vector2(350, 350); radiuses = [10, 100, 300]; @@ -48,6 +49,10 @@ const square = (x) => x * x; const checkCircle = (x, y, radius) => Math.abs(Math.sqrt(square(x - imageMid.x) + square(y - imageMid.y)) - radius) < circleWidth; +const lineLen = (line) => line.end.subtract(line.start).length(); + +const getLineMid = (line) => line.end.add(line.start).divide(2); + function blackwhite(img) { const picLength = img.width * img.height; @@ -221,7 +226,7 @@ function findDistanceToLine(point, linePos, lineNormVector){ } function findlines(matrix){ - const lines = []; + let lines = []; const h = matrix.length; const w = matrix[0].length; @@ -259,6 +264,54 @@ function findlines(matrix){ } } console.log('Found lines: ' + lines.length); + lines = lines.filter((line) => lineLen(line) > MIN_LINE_LEN); + return lines; +} + +function sortLines(lines){ + const getLinePosAngle = (line) => { + const vector = getLineMid(line).subtract(imageMid); + return Vector2.getAngle(vector); + } + + // const getCorrectAngle = (line) => { + // const angle = -getLinePosAngle(line); + // let angle2 = angle; + // angle2 = angle2 < 0 ? 2 * Math.PI + angle2 : angle2; + // return angle2; + // } + + // const compare = (a, b) => getCorrectAngle(a) - getCorrectAngle(b); + const compare = (a, b) => getLinePosAngle(a) - getLinePosAngle(b); + lines.sort(compare); + + // const colors = ['red', 'orange', 'green', 'cyan', 'blue', 'purple']; + + // for(let i = 0; i < lines.length; i++){ + // ctx2.strokeStyle = colors[i >= colors.length ? colors.length - 1 : i]; + // drawCircle(ctx2, getLineMid(lines[i])); + // //console.log(getCorrectAngle(lines[i])); + // } +} + +function getLineLengths(lines){ + let startLen = lineLen(lines[0]) + let longestLine = startLen; + let shortestLine = startLen; + for(let i = 1; i < lines.length; i++){ + const len = lineLen(lines[i]); + longestLine = len > longestLine ? len : longestLine; + shortestLine = len < shortestLine ? len : shortestLine; + } + const maxoffset = 0.01; + const maxlen = longestLine - shortestLine + maxoffset; + const rays = []; + for(const line of lines){ + const rayValue = Math.floor((lineLen(line) - shortestLine) / maxlen * 16); + rays.push(rayValue) + } + console.log(rays); + return rays; } function onLoad(){ @@ -283,7 +336,15 @@ function onLoad(){ console.log('Image is not scode'); } - findlines(matrix); + const lines = findlines(matrix); + + sortLines(lines); + + const rays = getLineLengths(lines); + + getLink(rays, (response) => { + console.log(response); + }) ctx2.strokeStyle = 'red'; diff --git a/front/script/script.js b/front/script/script.js index 13ef939..c728ef0 100644 --- a/front/script/script.js +++ b/front/script/script.js @@ -30,6 +30,7 @@ const onInput = () => { } getRays(link, (data) => { + console.log(data.rays); drawScode(data.rays, bg, color); }) } From 8f6943b3cec21e8feb2bae6d8dc21eaf018fcb8d Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 18:07:10 +0300 Subject: [PATCH 6/9] Done recognizing algorithm for ideal conditions(needs refactor and improvements) --- front/script/algorithm.js | 101 ++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/front/script/algorithm.js b/front/script/algorithm.js index cf8009d..e6a89d6 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -1,5 +1,7 @@ const DIAGONAL = Math.sqrt(2); +const RAYS_COUNT = 32; + const MAX_PATH_ITERATIONS = 4000; const PIX_DATA_LEN = 4; @@ -49,10 +51,18 @@ const square = (x) => x * x; const checkCircle = (x, y, radius) => Math.abs(Math.sqrt(square(x - imageMid.x) + square(y - imageMid.y)) - radius) < circleWidth; -const lineLen = (line) => line.end.subtract(line.start).length(); +const lineVec = (line) => line.end.subtract(line.start); + +const lineLen = (line) => lineVec(line).length(); const getLineMid = (line) => line.end.add(line.start).divide(2); +const getOppositeRayIndx = (index, raysCount = RAYS_COUNT) => (index + RAYS_COUNT / 2) % RAYS_COUNT; + +const getLeftPerpendicularRayIndx = (ndex, raysCount = RAYS_COUNT) => (index + RAYS_COUNT / 4) % RAYS_COUNT; + +const getRightPerpendicularRayIndx = (index, raysCount = RAYS_COUNT) => (index + 3 * RAYS_COUNT / 4) % RAYS_COUNT; + function blackwhite(img) { const picLength = img.width * img.height; @@ -294,7 +304,30 @@ function sortLines(lines){ // } } -function getLineLengths(lines){ +function getLineLengths(linelengths){ + let startLen = linelengths[0]; + let longestLine = startLen; + let shortestLine = startLen; + for(let i = 1; i < linelengths.length; i++){ + const len = linelengths[i]; + longestLine = len > longestLine ? len : longestLine; + shortestLine = len < shortestLine ? len : shortestLine; + } + const maxlen = longestLine - shortestLine; + const rays = []; + for(const line of linelengths){ + //let rayValue = Math.floor((line - shortestLine) / maxlen * 16); + //let rayValue = (line - shortestLine) / maxlen * 15; + let rayValue = Math.round((line - shortestLine) / maxlen * 15); + //rayValue = rayValue >= 16 ? 15 : rayValue; + rays.push(rayValue) + } + return rays; +} + +function normalizeLengths(lines){ + const lengths = lines.map((line) => lineLen(line)); + let startLen = lineLen(lines[0]) let longestLine = startLen; let shortestLine = startLen; @@ -303,15 +336,61 @@ function getLineLengths(lines){ longestLine = len > longestLine ? len : longestLine; shortestLine = len < shortestLine ? len : shortestLine; } - const maxoffset = 0.01; - const maxlen = longestLine - shortestLine + maxoffset; + const maxlen = longestLine - shortestLine; const rays = []; for(const line of lines){ - const rayValue = Math.floor((lineLen(line) - shortestLine) / maxlen * 16); + let rayValue = Math.floor((lineLen(line) - shortestLine) / maxlen * 16); + // let rayValue = Math.round((lineLen(line) - shortestLine) / maxlen * 15); + rayValue = rayValue >= 16 ? 15 : rayValue; rays.push(rayValue) } - console.log(rays); - return rays; + + const len = rays.length; + const sides = 4; + const step = len / sides; + + let startFound = false; + let iterator = 0; + const neededLen = [15, 15, 0, 15]; + + while (!startFound && iterator < len) { + let correct = true; + + neededLen.forEach((item, i) => { + const ind = (iterator + step * i) % len; + if (item !== rays[ind]) { + correct = false; + } + }); + + if (correct) { + startFound = true; + } else { + iterator++; + } + } + + if (!startFound) throw new Error('Something is wrong...'); + const stabilizedLines = lines.slice(iterator).concat(lines.slice(0, iterator)); + const stabilized = lengths.slice(iterator).concat(lengths.slice(0, iterator)); + + const top = 0; + const right = step; + const left = step * 3; + + //console.log(stabilized[top]); + //console.log(stabilized[right]); + //console.log(stabilized[bottom]); + //console.log(stabilized[left]); + + const coef = ((stabilized[right] + stabilized[left]) / 2) / stabilized[top]; + //console.log('Distortion(horizontal/vertical): ' + coef); + + for(let i = 0; i < stabilizedLines.length; i++){ + let angle = -Vector2.getAngle(lineVec(stabilizedLines[i])) - -Vector2.getAngle(lineVec(stabilizedLines[0]).rotate(-Math.PI / 2)); + stabilized[i] += stabilized[i] * Math.abs(Math.cos(angle)) * (1 - coef); + } + return stabilized; } function onLoad(){ @@ -340,10 +419,12 @@ function onLoad(){ sortLines(lines); - const rays = getLineLengths(lines); - + const rays = getLineLengths(normalizeLengths(lines)); + console.log('RecognizedRays:', rays); getLink(rays, (response) => { - console.log(response); + console.log(response); + const { link } = response; + $('#response-video').attr('src', link); }) ctx2.strokeStyle = 'red'; From 3956d59f1c2758b931f1380d68a30292e05cfd52 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 18:08:26 +0300 Subject: [PATCH 7/9] Small fix --- front/script/ajax.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/script/ajax.js b/front/script/ajax.js index b374c2c..43e754f 100644 --- a/front/script/ajax.js +++ b/front/script/ajax.js @@ -1,4 +1,4 @@ -const localhost = 'http://localhost:3000'; +const localhost = 'http://localhost:8080'; function getRays(link, cb) { const dataGetRays = { link }; From de5f1d781939c3e3fed974567b58236d73f141c7 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 18:35:50 +0300 Subject: [PATCH 8/9] Add blackwhite matrix clear around scode --- front/script/algorithm.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/front/script/algorithm.js b/front/script/algorithm.js index e6a89d6..97c0fcf 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -30,9 +30,9 @@ let correctPercentage = [ {min: 0, max: 0} ]; -let imageMid = new Vector2(350, 350); +const imageMid = new Vector2(350, 350); -radiuses = [10, 100, 300]; +const radiuses = [10, 100, 300]; const circleWidth = 0.5; @@ -123,7 +123,9 @@ function getMatrix(img){ matrix[j] = []; for(let i = 0; i < row; i++){ const ind = PIX_DATA_LEN * j * row + PIX_DATA_LEN * i; - const pixel = img.data[ind] >= BLACKWHITE_MID_THRESHOLD ? 0 : 1; + const x = i - imageMid.x; + const y = j - imageMid.y; + const pixel = Math.sqrt(x * x + y * y) < radiuses[2] && img.data[ind] < BLACKWHITE_MID_THRESHOLD ? 1 : 0; matrix[j].push(pixel); } } @@ -412,7 +414,8 @@ function onLoad(){ if(checkIfScode(matrix)){ console.log('Image is scode!'); } else { - console.log('Image is not scode'); + console.log('Image is not scode'); + return; } const lines = findlines(matrix); From 2903428c32a6f4ce16f654781016c9e12ed720f3 Mon Sep 17 00:00:00 2001 From: YAGoOaR Date: Wed, 12 May 2021 18:50:07 +0300 Subject: [PATCH 9/9] Remove commented code --- front/script/algorithm.js | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/front/script/algorithm.js b/front/script/algorithm.js index 97c0fcf..f8422f3 100644 --- a/front/script/algorithm.js +++ b/front/script/algorithm.js @@ -286,24 +286,8 @@ function sortLines(lines){ return Vector2.getAngle(vector); } - // const getCorrectAngle = (line) => { - // const angle = -getLinePosAngle(line); - // let angle2 = angle; - // angle2 = angle2 < 0 ? 2 * Math.PI + angle2 : angle2; - // return angle2; - // } - - // const compare = (a, b) => getCorrectAngle(a) - getCorrectAngle(b); const compare = (a, b) => getLinePosAngle(a) - getLinePosAngle(b); lines.sort(compare); - - // const colors = ['red', 'orange', 'green', 'cyan', 'blue', 'purple']; - - // for(let i = 0; i < lines.length; i++){ - // ctx2.strokeStyle = colors[i >= colors.length ? colors.length - 1 : i]; - // drawCircle(ctx2, getLineMid(lines[i])); - // //console.log(getCorrectAngle(lines[i])); - // } } function getLineLengths(linelengths){ @@ -318,10 +302,7 @@ function getLineLengths(linelengths){ const maxlen = longestLine - shortestLine; const rays = []; for(const line of linelengths){ - //let rayValue = Math.floor((line - shortestLine) / maxlen * 16); - //let rayValue = (line - shortestLine) / maxlen * 15; let rayValue = Math.round((line - shortestLine) / maxlen * 15); - //rayValue = rayValue >= 16 ? 15 : rayValue; rays.push(rayValue) } return rays; @@ -342,7 +323,6 @@ function normalizeLengths(lines){ const rays = []; for(const line of lines){ let rayValue = Math.floor((lineLen(line) - shortestLine) / maxlen * 16); - // let rayValue = Math.round((lineLen(line) - shortestLine) / maxlen * 15); rayValue = rayValue >= 16 ? 15 : rayValue; rays.push(rayValue) } @@ -380,13 +360,7 @@ function normalizeLengths(lines){ const right = step; const left = step * 3; - //console.log(stabilized[top]); - //console.log(stabilized[right]); - //console.log(stabilized[bottom]); - //console.log(stabilized[left]); - const coef = ((stabilized[right] + stabilized[left]) / 2) / stabilized[top]; - //console.log('Distortion(horizontal/vertical): ' + coef); for(let i = 0; i < stabilizedLines.length; i++){ let angle = -Vector2.getAngle(lineVec(stabilizedLines[i])) - -Vector2.getAngle(lineVec(stabilizedLines[0]).rotate(-Math.PI / 2)); @@ -409,6 +383,12 @@ function onLoad(){ blackwhite(img); ctx2.putImageData(img, 0, 0); + ctx2.strokeStyle = 'red'; + + for(let i = 0; i < 3; i++){ + drawCircle(ctx2, imageMid, radiuses[i]); + } + const matrix = getMatrix(img); if(checkIfScode(matrix)){ @@ -429,12 +409,6 @@ function onLoad(){ const { link } = response; $('#response-video').attr('src', link); }) - - ctx2.strokeStyle = 'red'; - - for(let i = 0; i < 3; i++){ - drawCircle(ctx2, imageMid, radiuses[i]); - } } document.getElementById('makePhoto').addEventListener('click', function() {