qr code detector, marker detector
This commit is contained in:
24
vendor/ts-aruco/samples/.gitignore
vendored
Normal file
24
vendor/ts-aruco/samples/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
41
vendor/ts-aruco/samples/debug-posit.html
vendored
Normal file
41
vendor/ts-aruco/samples/debug-posit.html
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Augmented Reality</title>
|
||||
|
||||
<script type="module" src="/src/debug-posit.ts"></script>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="text-align: center; font-family: monospace;">
|
||||
|
||||
<video id="video" width=320 height=240 autoplay="true" style="display:none;"></video>
|
||||
|
||||
<div style="margin: 10px;"><strong>-= Augmented Reality =-</strong></div>
|
||||
<div style="width: 100%;">
|
||||
<div style="width: 650px; margin-left:auto; margin-right:auto;">
|
||||
<canvas id="canvas" style="width: 320px; height: 240px; float: left; border: solid 1px black;"></canvas>
|
||||
<div id="container" style="width: 320px; height: 240px; float: left; border: solid 1px black; background: green;">
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<div style="float: left; border: solid 1px black;">
|
||||
<div id="container1" style="width: 320px; height: 240px; background: red;"></div>
|
||||
<div id="pose1"></div>
|
||||
</div>
|
||||
<div style="float: left; border: solid 1px black;">
|
||||
<div id="container2" style="width: 320px; height: 240px; background: blue;"></div>
|
||||
<div id="pose2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<div style="margin: 15px;"><strong>Powered by <a href="http://code.google.com/p/js-aruco/">js-aruco</a> and <a
|
||||
href="https://github.com/mrdoob/three.js">Three.js</a></strong></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
21
vendor/ts-aruco/samples/debug.html
vendored
Normal file
21
vendor/ts-aruco/samples/debug.html
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Augmented Reality Marker Detector</title>
|
||||
|
||||
<script type="module" src="/src/debug.ts"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: monospace;">
|
||||
|
||||
<center>
|
||||
<div style="margin: 10px;"><strong>-= Augmented Reality Marker Detector =-</strong></div>
|
||||
<video id="video" autoplay="true" style="width:320px; height:240px; display:none;"></video>
|
||||
<canvas id="canvas" style="width:960px; height:620px;"></canvas>
|
||||
<div style="margin: 15px;"><strong>Powered by <a href="http://code.google.com/p/js-aruco/">js-aruco</a></strong>
|
||||
</div>
|
||||
</center>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
19
vendor/ts-aruco/samples/getusermedia.html
vendored
Normal file
19
vendor/ts-aruco/samples/getusermedia.html
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Augmented Reality Marker Detector</title>
|
||||
</head>
|
||||
|
||||
<body style="font-family: monospace;">
|
||||
<script type="module" src="/src/getusermedia.ts"></script>
|
||||
<center>
|
||||
<div style="margin: 10px;"><strong>-= Augmented Reality Marker Detector =-</strong></div>
|
||||
<video id="video" autoplay="true" style="display:none;"></video>
|
||||
<canvas id="canvas" style="width:640px; height:480px;"></canvas>
|
||||
<div style="margin: 15px;"><strong>Powered by <a href="http://code.google.com/p/js-aruco/">js-aruco</a></strong>
|
||||
</div>
|
||||
</center>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
18
vendor/ts-aruco/samples/index.html
vendored
Normal file
18
vendor/ts-aruco/samples/index.html
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Aruco Examples ported to typescript</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Aruco demos</h1>
|
||||
<a href="debug.html">Debug</a>
|
||||
<a href="debug-posit.html">Debug Posit</a>
|
||||
<a href="getusermedia.html">Get user media</a>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1226
vendor/ts-aruco/samples/package-lock.json
generated
vendored
Normal file
1226
vendor/ts-aruco/samples/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
vendor/ts-aruco/samples/package.json
vendored
Normal file
19
vendor/ts-aruco/samples/package.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "samples",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "^0.161.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"three": "^0.161.0"
|
||||
}
|
||||
}
|
||||
BIN
vendor/ts-aruco/samples/public/earth.jpg
vendored
Normal file
BIN
vendor/ts-aruco/samples/public/earth.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
264
vendor/ts-aruco/samples/src/debug-posit.ts
vendored
Normal file
264
vendor/ts-aruco/samples/src/debug-posit.ts
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
import { Detector, type Marker } from '../../src/aruco';
|
||||
import { type CVPoint } from '../../src/cv';
|
||||
import { Posit } from '../../src/posit1';
|
||||
|
||||
import * as THREE from 'three';
|
||||
|
||||
let video: HTMLVideoElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let context: CanvasRenderingContext2D;
|
||||
|
||||
let imageData: ImageData;
|
||||
let detector: Detector;
|
||||
let posit: Posit;
|
||||
let renderer1: THREE.WebGLRenderer;
|
||||
let renderer2: THREE.WebGLRenderer;
|
||||
let renderer3: THREE.WebGLRenderer;
|
||||
let scene1: THREE.Scene;
|
||||
let scene2: THREE.Scene;
|
||||
let scene3: THREE.Scene;
|
||||
let scene4: THREE.Scene;
|
||||
|
||||
let camera1: THREE.PerspectiveCamera;
|
||||
let camera2: THREE.PerspectiveCamera;
|
||||
let camera3: THREE.OrthographicCamera;
|
||||
let camera4: THREE.PerspectiveCamera;
|
||||
|
||||
let plane1: THREE.Object3D;
|
||||
let plane2: THREE.Object3D;
|
||||
let model: THREE.Object3D;
|
||||
let texture: THREE.Object3D;
|
||||
let step = 0.0;
|
||||
|
||||
const modelSize = 35.0; // millimeters
|
||||
|
||||
function onLoad(): void {
|
||||
video = document.getElementById('video') as HTMLVideoElement;
|
||||
canvas = document.getElementById('canvas') as HTMLCanvasElement;
|
||||
context = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
|
||||
canvas.width = parseInt(canvas.style.width);
|
||||
canvas.height = parseInt(canvas.style.height);
|
||||
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.then(function (stream) {
|
||||
video.srcObject = stream;
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log(err.name + ': ' + err.message);
|
||||
}
|
||||
);
|
||||
|
||||
detector = new Detector();
|
||||
posit = new Posit(modelSize, canvas.width);
|
||||
|
||||
createRenderers();
|
||||
createScenes();
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
function tick(): void {
|
||||
requestAnimationFrame(tick);
|
||||
|
||||
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
||||
snapshot();
|
||||
|
||||
const markers: Marker[] = detector.detect(imageData);
|
||||
drawCorners(markers);
|
||||
updateScenes(markers);
|
||||
|
||||
render();
|
||||
}
|
||||
};
|
||||
|
||||
function snapshot(): void {
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
function drawCorners(markers: Marker[]): void {
|
||||
context.lineWidth = 3;
|
||||
|
||||
for (let i = 0; i < markers.length; ++i) {
|
||||
const corners = markers[i].corners;
|
||||
|
||||
context.strokeStyle = 'red';
|
||||
context.beginPath();
|
||||
|
||||
for (let j = 0; j < corners.points.length; ++j) {
|
||||
let corner: CVPoint = corners.points[j];
|
||||
context.moveTo(corner.x, corner.y);
|
||||
corner = corners.points[(j + 1) % corners.points.length];
|
||||
context.lineTo(corner.x, corner.y);
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
context.closePath();
|
||||
|
||||
context.strokeStyle = 'green';
|
||||
context.strokeRect(corners.points[0].x - 2, corners.points[0].y - 2, 4, 4);
|
||||
}
|
||||
};
|
||||
|
||||
function createRenderers(): void {
|
||||
renderer1 = new THREE.WebGLRenderer();
|
||||
renderer1.setClearColor(0xffff00, 1);
|
||||
renderer1.setSize(canvas.width, canvas.height);
|
||||
document.getElementById('container1')!.appendChild(renderer1.domElement);
|
||||
scene1 = new THREE.Scene();
|
||||
camera1 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
|
||||
scene1.add(camera1);
|
||||
|
||||
renderer2 = new THREE.WebGLRenderer();
|
||||
renderer2.setClearColor(0xffff00, 1);
|
||||
renderer2.setSize(canvas.width, canvas.height);
|
||||
document.getElementById('container2')!.appendChild(renderer2.domElement);
|
||||
scene2 = new THREE.Scene();
|
||||
camera2 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
|
||||
scene2.add(camera2);
|
||||
|
||||
renderer3 = new THREE.WebGLRenderer();
|
||||
renderer3.setClearColor(0xffffff, 1);
|
||||
renderer3.setSize(canvas.width, canvas.height);
|
||||
document.getElementById('container')!.appendChild(renderer3.domElement);
|
||||
|
||||
scene3 = new THREE.Scene();
|
||||
camera3 = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
|
||||
scene3.add(camera3);
|
||||
|
||||
scene4 = new THREE.Scene();
|
||||
camera4 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
|
||||
scene4.add(camera4);
|
||||
};
|
||||
|
||||
function render(): void {
|
||||
renderer1.clear();
|
||||
renderer1.render(scene1, camera1);
|
||||
|
||||
renderer2.clear();
|
||||
renderer2.render(scene2, camera2);
|
||||
|
||||
renderer3.autoClear = false;
|
||||
renderer3.clear();
|
||||
renderer3.render(scene3, camera3);
|
||||
renderer3.render(scene4, camera4);
|
||||
};
|
||||
|
||||
function createScenes(): void {
|
||||
plane1 = createPlane();
|
||||
scene1.add(plane1);
|
||||
|
||||
plane2 = createPlane();
|
||||
scene2.add(plane2);
|
||||
|
||||
texture = createTexture();
|
||||
scene3.add(texture);
|
||||
|
||||
model = createModel();
|
||||
scene4.add(model);
|
||||
};
|
||||
|
||||
function createPlane(): THREE.Object3D {
|
||||
const object = new THREE.Object3D();
|
||||
const geometry = new THREE.PlaneGeometry(1, 1);
|
||||
const material = new THREE.MeshNormalMaterial();
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
object.rotation.order = 'YXZ';
|
||||
|
||||
object.add(mesh);
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
function createTexture(): THREE.Object3D {
|
||||
const texture = new THREE.VideoTexture(video);
|
||||
const object = new THREE.Object3D();
|
||||
const geometry = new THREE.PlaneGeometry(1.0, 1.0);
|
||||
const material = new THREE.MeshBasicMaterial({ map: texture, depthTest: false, depthWrite: false });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
object.position.z = -1;
|
||||
|
||||
object.add(mesh);
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
function createModel(): THREE.Object3D {
|
||||
const object = new THREE.Object3D();
|
||||
const geometry = new THREE.SphereGeometry(0.5, 15, 15, Math.PI);
|
||||
|
||||
const texture = new THREE.TextureLoader().load('earth.jpg');
|
||||
const material = new THREE.MeshBasicMaterial({ map: texture });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
object.add(mesh);
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
function updateScenes(markers: Marker[]): void {
|
||||
if (markers.length > 0) {
|
||||
const corners = markers[0].corners;
|
||||
|
||||
for (let i = 0; i < corners.points.length; ++i) {
|
||||
const corner = corners.points[i];
|
||||
|
||||
corner.x = corner.x - (canvas.width / 2);
|
||||
corner.y = (canvas.height / 2) - corner.y;
|
||||
}
|
||||
|
||||
const pose = posit.pose(corners.points);
|
||||
|
||||
updateObject(plane1, pose.bestRotation, pose.bestTranslation);
|
||||
updateObject(plane2, pose.alternativeRotation, pose.alternativeTranslation);
|
||||
updateObject(model, pose.bestRotation, pose.bestTranslation);
|
||||
|
||||
updatePose('pose1', pose.bestError, pose.bestRotation, pose.bestTranslation);
|
||||
updatePose('pose2', pose.alternativeError, pose.alternativeRotation, pose.alternativeTranslation);
|
||||
|
||||
step += 0.025;
|
||||
|
||||
model.rotation.z -= step;
|
||||
}
|
||||
// //@ts-ignore
|
||||
//texture.children[0].material.map.needsUpdate = true;
|
||||
};
|
||||
|
||||
function updateObject(object: THREE.Object3D, rotation: number[][], translation: number[]): void {
|
||||
object.scale.x = modelSize;
|
||||
object.scale.y = modelSize;
|
||||
object.scale.z = modelSize;
|
||||
|
||||
object.rotation.x = -Math.asin(-rotation[1][2]);
|
||||
object.rotation.y = -Math.atan2(rotation[0][2], rotation[2][2]);
|
||||
object.rotation.z = Math.atan2(rotation[1][0], rotation[1][1]);
|
||||
|
||||
object.position.x = translation[0];
|
||||
object.position.y = translation[1];
|
||||
object.position.z = -translation[2];
|
||||
};
|
||||
|
||||
function updatePose(id: string, error: number, rotation: number[][], translation: number[]): void {
|
||||
const yaw = -Math.atan2(rotation[0][2], rotation[2][2]);
|
||||
const pitch = -Math.asin(-rotation[1][2]);
|
||||
const roll = Math.atan2(rotation[1][0], rotation[1][1]);
|
||||
|
||||
const d = document.getElementById(id);
|
||||
if (d !== null) {
|
||||
d.innerHTML = ' error: ' + error +
|
||||
'<br/>' +
|
||||
' x: ' + (translation[0] | 0) +
|
||||
' y: ' + (translation[1] | 0) +
|
||||
' z: ' + (translation[2] | 0) +
|
||||
'<br/>' +
|
||||
' yaw: ' + Math.round(-yaw * 180.0 / Math.PI) +
|
||||
' pitch: ' + Math.round(-pitch * 180.0 / Math.PI) +
|
||||
' roll: ' + Math.round(roll * 180.0 / Math.PI);
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = onLoad;
|
||||
170
vendor/ts-aruco/samples/src/debug.ts
vendored
Normal file
170
vendor/ts-aruco/samples/src/debug.ts
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
import { Detector, type Marker } from '../../src/aruco.ts';
|
||||
import { type CVContour, otsu, threshold, warp } from '../../src/cv.ts';
|
||||
|
||||
let camera: HTMLVideoElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let context: CanvasRenderingContext2D;
|
||||
let imageData: ImageData;
|
||||
let detector: Detector;
|
||||
|
||||
let debugImage: ImageData;
|
||||
let warpImage: ImageData;
|
||||
let homographyImage: ImageData;
|
||||
|
||||
export const onLoad = (): void => {
|
||||
camera = document.getElementById('video') as HTMLVideoElement;
|
||||
canvas = document.getElementById('canvas') as HTMLCanvasElement;
|
||||
context = canvas!.getContext('2d')!;
|
||||
|
||||
camera.width = 320;
|
||||
camera.height = 240;
|
||||
|
||||
canvas.width = parseInt(canvas.style.width);
|
||||
canvas.height = parseInt(canvas.style.height);
|
||||
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.then((stream) => {
|
||||
camera.srcObject = stream;
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log(err.name + ': ' + err.message);
|
||||
}
|
||||
);
|
||||
|
||||
imageData = context.getImageData(0, 0, camera.width, camera.height);
|
||||
detector = new Detector();
|
||||
|
||||
debugImage = context.createImageData(camera.width, camera.height);
|
||||
warpImage = context.createImageData(49, 49);
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
const tick = (): void => {
|
||||
requestAnimationFrame(tick);
|
||||
|
||||
if (camera.readyState === camera.HAVE_ENOUGH_DATA) {
|
||||
snapshot();
|
||||
|
||||
const markers = detector.detect(imageData);
|
||||
drawDebug();
|
||||
drawCorners(markers);
|
||||
drawId(markers);
|
||||
}
|
||||
};
|
||||
|
||||
const snapshot = (): void => {
|
||||
context.drawImage(camera, 0, 0, camera.width, camera.height);
|
||||
imageData = context.getImageData(0, 0, camera.width, camera.height);
|
||||
};
|
||||
|
||||
const drawDebug = (): void => {
|
||||
const width = camera.width; const height = camera.height;
|
||||
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
context.putImageData(createImage(detector.grey!, debugImage), width, 0);
|
||||
context.putImageData(createImage(detector.thres!, debugImage), width * 2, 0);
|
||||
|
||||
drawContours(detector.contours, 0, height, function (hole: any) { return hole ? 'magenta' : 'blue'; });
|
||||
drawContours(detector.polys, width, height, function () { return 'green'; });
|
||||
drawContours(detector.candidates, width * 2, height, function () { return 'red'; });
|
||||
|
||||
drawWarps(detector.grey!, detector.candidates, height * 2 + 20);
|
||||
};
|
||||
|
||||
const drawContours = (contours: CVContour[], x: number, y: number, fn: any): void => {
|
||||
let i = contours.length; let j; let contour; let point;
|
||||
|
||||
while (i--) {
|
||||
contour = contours[i];
|
||||
|
||||
context.strokeStyle = fn(contour.hole);
|
||||
context.beginPath();
|
||||
|
||||
for (j = 0; j < contour.points?.length; ++j) {
|
||||
point = contour.points[j];
|
||||
context.moveTo(x + point.x, y + point.y);
|
||||
point = contour.points[(j + 1) % contour.points.length];
|
||||
context.lineTo(x + point.x, y + point.y);
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
context.closePath();
|
||||
}
|
||||
};
|
||||
|
||||
const drawWarps = (imageSrc: ImageData, contours: CVContour[], y: number): void => {
|
||||
let i = contours.length;
|
||||
let contour;
|
||||
|
||||
const offset = (canvas.width - ((warpImage.width + 10) * contours.length)) / 2;
|
||||
while (i--) {
|
||||
contour = contours[i];
|
||||
|
||||
homographyImage = warp(imageSrc, contour, warpImage.width);
|
||||
context.putImageData(createImage(homographyImage, warpImage), offset + i * (warpImage.width + 10), y);
|
||||
|
||||
homographyImage = threshold(homographyImage, otsu(homographyImage));
|
||||
context.putImageData(createImage(homographyImage, warpImage), offset + i * (warpImage.width + 10), y + 60);
|
||||
}
|
||||
};
|
||||
|
||||
const drawCorners = (markers: Marker[]): void => {
|
||||
context.lineWidth = 3;
|
||||
|
||||
for (let i = 0; i !== markers.length; ++i) {
|
||||
const corners = markers[i].corners.points;
|
||||
|
||||
context.strokeStyle = 'red';
|
||||
context.beginPath();
|
||||
|
||||
for (let j = 0; j !== corners.length; ++j) {
|
||||
let corner = corners[j];
|
||||
context.moveTo(corner.x, corner.y);
|
||||
corner = corners[(j + 1) % corners.length];
|
||||
context.lineTo(corner.x, corner.y);
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
context.closePath();
|
||||
|
||||
context.strokeStyle = 'green';
|
||||
context.strokeRect(corners[0].x - 2, corners[0].y - 2, 4, 4);
|
||||
}
|
||||
};
|
||||
|
||||
const drawId = (markers: Marker[]): void => {
|
||||
context.strokeStyle = 'blue';
|
||||
context.lineWidth = 1;
|
||||
|
||||
for (let i = 0; i !== markers.length; ++i) {
|
||||
const corners = markers[i].corners.points;
|
||||
|
||||
let x = Infinity;
|
||||
let y = Infinity;
|
||||
|
||||
for (let j = 0; j !== corners.length; ++j) {
|
||||
const corner = corners[j];
|
||||
x = Math.min(x, corner.x);
|
||||
y = Math.min(y, corner.y);
|
||||
}
|
||||
|
||||
context.strokeText(`${markers[i].id}`, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
const createImage = (src: ImageData, dst: ImageData): ImageData => {
|
||||
let i = src.data.length; let j = (i * 4) + 3;
|
||||
|
||||
while (i--) {
|
||||
dst.data[j -= 4] = 255;
|
||||
dst.data[j - 1] = dst.data[j - 2] = dst.data[j - 3] = src.data[i];
|
||||
}
|
||||
|
||||
return dst;
|
||||
};
|
||||
|
||||
window.onload = onLoad;
|
||||
97
vendor/ts-aruco/samples/src/getusermedia.ts
vendored
Normal file
97
vendor/ts-aruco/samples/src/getusermedia.ts
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Detector, type Marker } from '../../src/aruco.ts';
|
||||
|
||||
let video: HTMLVideoElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let context: CanvasRenderingContext2D;
|
||||
let imageData: ImageData;
|
||||
let detector: Detector;
|
||||
|
||||
const onLoad = (): void => {
|
||||
video = document.getElementById('video')! as HTMLVideoElement;
|
||||
canvas = document.getElementById('canvas')! as HTMLCanvasElement;
|
||||
context = canvas.getContext('2d')!;
|
||||
|
||||
canvas.width = parseInt(canvas.style.width);
|
||||
canvas.height = parseInt(canvas.style.height);
|
||||
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.then(function (stream) {
|
||||
video.srcObject = stream;
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log(err.name + ': ' + err.message);
|
||||
}
|
||||
);
|
||||
|
||||
detector = new Detector();
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
const tick = (): void => {
|
||||
requestAnimationFrame(tick);
|
||||
|
||||
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
||||
snapshot();
|
||||
const markers = detector.detect(imageData);
|
||||
drawCorners(markers);
|
||||
drawId(markers);
|
||||
}
|
||||
};
|
||||
|
||||
const snapshot = (): void => {
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
const drawCorners = (markers: Marker[]): void => {
|
||||
let corners, corner, i, j;
|
||||
|
||||
context.lineWidth = 3;
|
||||
|
||||
for (i = 0; i !== markers.length; ++i) {
|
||||
corners = markers[i].corners.points;
|
||||
|
||||
context.strokeStyle = 'red';
|
||||
context.beginPath();
|
||||
|
||||
for (j = 0; j !== corners.length; ++j) {
|
||||
corner = corners[j];
|
||||
context.moveTo(corner.x, corner.y);
|
||||
corner = corners[(j + 1) % corners.length];
|
||||
context.lineTo(corner.x, corner.y);
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
context.closePath();
|
||||
|
||||
context.strokeStyle = 'green';
|
||||
context.strokeRect(corners[0].x - 2, corners[0].y - 2, 4, 4);
|
||||
}
|
||||
};
|
||||
|
||||
const drawId = (markers: Marker[]): void => {
|
||||
let corners, corner, x, y, i, j;
|
||||
|
||||
context.strokeStyle = 'blue';
|
||||
context.lineWidth = 1;
|
||||
|
||||
for (i = 0; i !== markers.length; ++i) {
|
||||
corners = markers[i].corners.points;
|
||||
|
||||
x = Infinity;
|
||||
y = Infinity;
|
||||
|
||||
for (j = 0; j !== corners.length; ++j) {
|
||||
corner = corners[j];
|
||||
|
||||
x = Math.min(x, corner.x);
|
||||
y = Math.min(y, corner.y);
|
||||
}
|
||||
|
||||
context.strokeText(`${markers[i].id}`, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = onLoad;
|
||||
1
vendor/ts-aruco/samples/src/vite-env.d.ts
vendored
Normal file
1
vendor/ts-aruco/samples/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
23
vendor/ts-aruco/samples/tsconfig.json
vendored
Normal file
23
vendor/ts-aruco/samples/tsconfig.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
16
vendor/ts-aruco/samples/vite.config.js
vendored
Normal file
16
vendor/ts-aruco/samples/vite.config.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { resolve } from "path";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
base: "https://axeljaeger.github.io/ts-aruco/",
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, "index.html"),
|
||||
getusermedia: resolve(__dirname, "getusermedia.html"),
|
||||
debug: resolve(__dirname, "debug.html"),
|
||||
debugPosit: resolve(__dirname, "debug-posit.html"),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user