From 326dae4acc33b2d1c45b1bcbcba36a0a581e225b Mon Sep 17 00:00:00 2001 From: Yuriy Maksymets <iurii.maksymets@gmail.com> Date: Sun, 10 Nov 2019 17:19:58 +0000 Subject: [PATCH] Simple Hough transform line detection --- __tests__/shape.test.js | 13 +++---- src/shapes.js | 75 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/__tests__/shape.test.js b/__tests__/shape.test.js index c8a2db9..201a159 100644 --- a/__tests__/shape.test.js +++ b/__tests__/shape.test.js @@ -13,25 +13,22 @@ describe("shape recognition", () => { test("should recognize a simple horizontal line", () => { const points = [[0, 0], [100, 0]] const result = recognizeFromPoints(points) - expect(result).toBe(Shapes.line) + expect(result.shape).toBe(Shapes.line) }) - test("should recognize a simple vertical line", () => { const points = [[0, 50], [0, -100]] const result = recognizeFromPoints(points) - expect(result).toBe(Shapes.line) + expect(result.shape).toBe(Shapes.line) }) - test("should recognize a slightly curve horizontal line", () => { - const points = [[0, 0], [30, 10], [100, 2]] + const points = [[0, 0], [30, 5], [100, 2]] const result = recognizeFromPoints(points) - expect(result).toBe(Shapes.line) + expect(result.shape).toBe(Shapes.line) }) - test("should not recognize a really curved horizontal line", () => { const points = [[0, 0], [30, 30], [100, -4]] const result = recognizeFromPoints(points) - expect(result).not.toBe(Shapes.line) + expect(result.shape).not.toBe(Shapes.line) }) }) diff --git a/src/shapes.js b/src/shapes.js index 2c827fd..72f8e71 100644 --- a/src/shapes.js +++ b/src/shapes.js @@ -1,8 +1,77 @@ +function dtor(a) { + return (Math.PI * a) / 180 +} +function cos(a) { + return Math.cos(dtor(a)) +} +function sin(a) { + return Math.sin(dtor(a)) +} + +const rhoStep = 5 +const angleStep = 90 +const numAngleCells = 180 / angleStep +const rhoMax = 1000 + +function findMaxInHough(accum, threshold) { + let max = 0 + // let bestRho = 0 + let bestTheta = 0 + for (let i = 0; i < numAngleCells; i++) { + for (let j = 0; j < accum[i].length; j++) { + if (accum[i][j] > max) { + max = accum[i][j] + // bestRho = j + bestTheta = i + } + } + } + // bestRho <<= 1 + // bestRho -= rhoMax + // bestRho *= rhoStep + bestTheta *= angleStep + + if (max > threshold) { + if (bestTheta === 90) { + return 90 + } else { + return 0 + } + } + return undefined +} + +function constructHoughAccumulator(accumulator, x, y) { + for (let thetaIndex = 0; thetaIndex < numAngleCells; thetaIndex++) { + const theta = thetaIndex * angleStep + let rho = x * cos(theta) + y * sin(theta) + rho = Math.floor(rho) + rho += rhoMax + rho >>= 1 + rho /= rhoStep + rho = Math.floor(rho) + if (accumulator[thetaIndex] == undefined) accumulator[thetaIndex] = [] + if (accumulator[thetaIndex][rho] == undefined) { + accumulator[thetaIndex][rho] = 1 + } else { + accumulator[thetaIndex][rho]++ + } + } +} + function recognizeFromPoints(points) { - return { - shape: Shapes.rectangle, - points, + const accum = Array(numAngleCells) + points.forEach((x) => constructHoughAccumulator(accum, ...x)) + const angle = findMaxInHough(accum, points.length - 1) + + if (angle !== undefined) { + return { + shape: Shapes.line, + points, + } } + + return {} } export const Shapes = { -- GitLab