提交 48bee7b7 编写于 作者: J Jerome Etienne

new version of aruco

上级 e09bba26
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<!-- three.js library -->
<script src='vendor/three.js/build/three.min.js'></script>
<!-- jsartookit -->
<script src='../vendor/jsartoolkit5/build/artoolkit.min.js'></script>
<script src='../vendor/jsartoolkit5/js/artoolkit.api.js'></script>
<!-- include threex.artoolkit -->
<script src='../threex-artoolkitsource.js'></script>
<script src='../threex-artoolkitcontext.js'></script>
<script src='../threex-artoolkitprofile.js'></script>
<script src='../threex-arbasecontrols.js'></script>
<script src='../threex-armarkercontrols.js'></script>
<script src='../threex-arsmoothedcontrols.js'></script>
<script>THREEx.ArToolkitContext.baseURL = '../'</script>
<!-- threex aruco -->
<script src='threex-aruco/vendor/js-aruco/src/svd.js'></script>
<script src='threex-aruco/vendor/js-aruco/src/posit1.js'></script>
<script src='threex-aruco/vendor/js-aruco/src/cv.js'></script>
<script src='threex-aruco/vendor/js-aruco/src/aruco.js'></script>
<script src='threex-aruco/threex-arucocontext.js'></script>
<script src='threex-aruco/threex-arucodebug.js'></script>
<body style='margin : 0px; overflow: hidden; font-family: Monospace;'><div style='position: absolute; top: 10px; width:100%; text-align: center; z-index: 1;'>
<a href="https://github.com/jeromeetienne/AR.js/" target="_blank">AR.js</a> - three.js camera transform
<br/>
Contact me any time at <a href='https://twitter.com/jerome_etienne' target='_blank'>@jerome_etienne</a>
</div><script>
//////////////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////////////
// init renderer
var renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setClearColor(new THREE.Color('lightgrey'), 0)
renderer.setSize( 640, 480 );
renderer.domElement.style.position = 'absolute'
renderer.domElement.style.top = '0px'
renderer.domElement.style.left = '0px'
document.body.appendChild( renderer.domElement );
// array of functions for the rendering loop
var onRenderFcts= [];
// init scene and camera
var scene = new THREE.Scene();
//////////////////////////////////////////////////////////////////////////////////
// Initialize a basic camera
//////////////////////////////////////////////////////////////////////////////////
// Create a camera
var camera = new THREE.Camera();
scene.add(camera);
////////////////////////////////////////////////////////////////////////////////
// handle arToolkitSource
////////////////////////////////////////////////////////////////////////////////
var arToolkitSource = new THREEx.ArToolkitSource({
// to read from the webcam
sourceType : 'webcam',
// // to read from an image
// sourceType : 'image',
// sourceUrl : THREEx.ArToolkitContext.baseURL + '../data/images/img.jpg',
// to read from a video
// sourceType : 'video',
// sourceUrl : THREEx.ArToolkitContext.baseURL + '../data/videos/headtracking.mp4',
})
arToolkitSource.init(function onReady(){
onResize()
})
// handle resize
window.addEventListener('resize', function(){
onResize()
})
function onResize(){
arToolkitSource.onResize()
arToolkitSource.copySizeTo(renderer.domElement)
if( arToolkitContext.arController !== null ){
arToolkitSource.copySizeTo(arToolkitContext.arController.canvas)
}
}
////////////////////////////////////////////////////////////////////////////////
// initialize arToolkitContext
////////////////////////////////////////////////////////////////////////////////
// create atToolkitContext
var arToolkitContext = new THREEx.ArToolkitContext({
cameraParametersUrl: THREEx.ArToolkitContext.baseURL + '../data/data/camera_para.dat',
detectionMode: 'mono',
})
// initialize it
arToolkitContext.initAruco(function onCompleted(){
// copy projection matrix to camera
camera.projectionMatrix.copy( arToolkitContext.getProjectionMatrix() );
})
// update artoolkit on every frame
onRenderFcts.push(function(){
if( arToolkitSource.ready === false ) return
arToolkitContext.update( arToolkitSource.domElement )
// update scene.visible if the marker is seen
scene.visible = camera.visible
})
////////////////////////////////////////////////////////////////////////////////
// Create a ArMarkerControls
////////////////////////////////////////////////////////////////////////////////
// init controls for camera
var markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
type : 'pattern',
patternUrl : THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro',
// patternUrl : THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji',
// as we controls the camera, set changeMatrixMode: 'cameraTransformMatrix'
changeMatrixMode: 'cameraTransformMatrix'
})
// as we do changeMatrixMode: 'cameraTransformMatrix', start with invisible scene
scene.visible = false
//////////////////////////////////////////////////////////////////////////////////
// add an object in the scene
//////////////////////////////////////////////////////////////////////////////////
// add a torus knot
var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshNormalMaterial({
transparent : true,
opacity: 0.5,
side: THREE.DoubleSide
});
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = geometry.parameters.height/2
scene.add( mesh );
var geometry = new THREE.TorusKnotGeometry(0.3,0.1,64,16);
var material = new THREE.MeshNormalMaterial();
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = 0.5
scene.add( mesh );
onRenderFcts.push(function(delta){
mesh.rotation.x += Math.PI*delta
})
//////////////////////////////////////////////////////////////////////////////////
// render the whole thing on the page
//////////////////////////////////////////////////////////////////////////////////
// render the scene
onRenderFcts.push(function(){
renderer.render( scene, camera );
})
// run the rendering loop
var lastTimeMsec= null
requestAnimationFrame(function animate(nowMsec){
// keep looping
requestAnimationFrame( animate );
// measure time
lastTimeMsec = lastTimeMsec || nowMsec-1000/60
var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
lastTimeMsec = nowMsec
// call each update function
onRenderFcts.forEach(function(onRenderFct){
onRenderFct(deltaMsec/1000, nowMsec/1000)
})
})
</script></body>
watch: build
fswatch -0 three.js/*.js | xargs -0 -n 1 -I {} make build
.PHONY: build
build:
cat vendor/js-aruco/src/aruco.js \
vendor/js-aruco/src/cv.js \
vendor/js-aruco/src/posit1.js \
vendor/js-aruco/src/svd.js \
threex-*.js > build/threex-aruco.js
minify: build
uglifyjs build/threex-aruco.js > build/threex-aruco-min.js
prepack: build
prepack build/threex-aruco.js --out build/threex-aruco-prepacked.js
Trying to use js-aruco as ar.js backend
- expose all the hardcoded parameters from AR.Detect in the debug,html
- thus you can tune them
---
# Performances
- jsaruco use a kernel size of 2 in adaptative thresholding
- could i reduce the resolution of the source image and use a kernel size of 1 ?
- it would produce more fps. what the difference would be ? create errors ?
- jsaruco - adaptiveThreshold is doing it on ALL bytes - so all channel ??? check if it is correct
- it use blackwhite image - it only needs 1 channel - 8 bits is already a lot to store blackwhite
- this mean 4 times more work than needed
- NOTES: unclear this is true - grayscale is packing it all in 1 channel. check it out ?
- in posit1: image difference is computed by a manathan distance. not a euclidian distance... how come ?
- this seems to intrduce an error without need (sqrt is nothing in js)
- ```imageDifference += Math.abs(sopImagePoints[i].x - oldSopImagePoints[i].x);```
- ```imageDifference += Math.abs(sopImagePoints[i].y - oldSopImagePoints[i].y);```
# How to include it in AR.js
- see how to include it in ar.js
- so basically a context and a controls
- the source can remain the same without trouble
- how to handle all the options between the various backend
- how to handle the development ?
- do you copy the files ?
- do i modify the master files
- seems to have only a few modifications
-
此差异已折叠。
<html>
<!-- <script src='vendor/Three.js'></script> -->
<script src='../../vendor/three.js/build/three.js'></script>
<script src='../vendor/js-aruco/src/svd.js'></script>
<script src='../vendor/js-aruco/src/posit1.js'></script>
<script src='../vendor/js-aruco/src/cv.js'></script>
<script src='../vendor/js-aruco/src/aruco.js'></script>
<script src='../threex-arucocontext.js'></script>
<script src='../threex-arucodebug.js'></script>
<div>
<form>
<label>clear canvas<input id='checkboxClearCanvas' name="imgsel" type="radio"></label>
<br/>
<label>draw video<input id='checkboxDrawVideo' name="imgsel" type="radio" checked="checked" ></label>
<br/>
<label>draw detector grey<input id='checkboxDetectorGrey' name="imgsel" type="radio"></label>
<br/>
<label>draw detector threshold<input id='checkboxDetectorThreshold' name="imgsel" type="radio"></label>
</form>
<label>draw marker corners<input id='checkboxMarkerCorners' type="checkbox" checked="checked" ></label>
<br/>
<label>draw marker ids<input id='checkboxMarkerId' type="checkbox" checked="checked" ></label>
<br/>
<label>draw contours contours<input id='checkboxContoursContours' type="checkbox"></label>
<br/>
<label>draw contours polys<input id='checkboxContoursPolys' type="checkbox"></label>
<br/>
<label>draw contours candiddates<input id='checkboxContoursCandidates' type="checkbox"></label>
</div>
<body style='background-color: darkgray;'>
<div id='webGLContainer' style='display: inline;'></div>
<script>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var videoElement = document.createElement('video')
// videoElement.width = 320
// videoElement.height = 240
videoElement.autoplay = true
//////////////////////////////////////////////////////////////////////////////
// Code Separator
//////////////////////////////////////////////////////////////////////////////
navigator.getUserMedia({video:true}, function (stream){
if (window.URL) {
videoElement.src = window.URL.createObjectURL(stream);
} else if (videoElement.mozSrcObject !== undefined) {
videoElement.mozSrcObject = stream;
} else {
videoElement.src = stream;
}
},
function(error){
}
);
var markerSize = 1.0; //millimeters
var arucoContext = new THREEx.ArucoContext(markerSize)
var arucoDebug = new THREEx.ArucoDebug(arucoContext)
document.body.appendChild(arucoDebug.canvasElement)
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff, 1);
renderer.setSize(arucoContext.canvas.width, arucoContext.canvas.height);
document.getElementById('webGLContainer').appendChild(renderer.domElement);
var sceneOrtho = new THREE.Scene();
var cameraOrtho = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
sceneOrtho.add(cameraOrtho);
var scenePersp = new THREE.Scene();
var cameraPersp = new THREE.PerspectiveCamera(42, arucoContext.canvas.width / arucoContext.canvas.height, 0.01, 100);
scenePersp.add(cameraPersp);
//////////////////////////////////////////////////////////////////////////////
// Code Separator
//////////////////////////////////////////////////////////////////////////////
var videoTexture = new THREE.Texture(videoElement)
videoTexture.minFilter = THREE.LinearFilter
var geometry = new THREE.PlaneGeometry(1.0, 1.0)
var material = new THREE.MeshBasicMaterial({
map: videoTexture,
depthTest: false,
depthWrite: false
})
var videoMesh = new THREE.Mesh(geometry, material);
videoMesh.position.z = -1;
sceneOrtho.add(videoMesh);
var geometry = new THREE.PlaneGeometry(1.0, 1.0, 10, 10)
var material = new THREE.MeshBasicMaterial( {
color: 'hotpink',
wireframe: true
} )
var model = new THREE.Mesh(geometry, material);
var arWorldRoot = new THREE.Group
arWorldRoot.add(model)
scenePersp.add(arWorldRoot);
//////////////////////////////////////////////////////////////////////////////
// render loop
//////////////////////////////////////////////////////////////////////////////
var lastDetectionAt = null
requestAnimationFrame(function onAnimationFrame(){
// update videoMesh
videoMesh.material.map.needsUpdate = true;
var present = Date.now()/1000
if( lastDetectionAt === null || present-lastDetectionAt >= 1/30){
lastDetectionAt = Date.now()/1000
// if( videoElement.readyState >= videoElement.HAVE_CURRENT_DATA ){
// detect markers in imageData
var detectedMarkers = arucoContext.detect(videoElement)
if( detectedMarkers.length > 0 ){
var detectedMarker = detectedMarkers[0]
THREEx.ArucoContext.updateObject3D(arWorldRoot, detectedMarker);
arWorldRoot.visible = true
}else{
arWorldRoot.visible = false
}
if( document.querySelector('#checkboxClearCanvas').checked ) arucoDebug.clear()
if( document.querySelector('#checkboxDrawVideo').checked ) arucoDebug.drawVideo(videoElement)
if( document.querySelector('#checkboxDetectorGrey').checked ) arucoDebug.drawDetectorGrey()
if( document.querySelector('#checkboxDetectorThreshold').checked ) arucoDebug.drawDetectorThreshold()
if( document.querySelector('#checkboxMarkerCorners').checked ) arucoDebug.drawMarkerCorners(detectedMarkers)
if( document.querySelector('#checkboxMarkerId').checked ) arucoDebug.drawMarkerIDs(detectedMarkers)
if( document.querySelector('#checkboxContoursContours').checked ) arucoDebug.drawContoursContours()
if( document.querySelector('#checkboxContoursPolys').checked ) arucoDebug.drawContoursPolys()
if( document.querySelector('#checkboxContoursCandidates').checked ) arucoDebug.drawContoursCandidates()
}
// render scene
renderer.autoClear = false;
renderer.clear();
renderer.render(sceneOrtho, cameraOrtho);
renderer.render(scenePersp, cameraPersp);
requestAnimationFrame(onAnimationFrame);
});
</script>
<style media="screen">
img {
width: 196px;
height: 196px;
padding: 0em;
margin: 0;
}
</style>
<br/>
<div>
<img src="images/1001.png"/>
<img src="images/1002.png"/>
<img src="images/1003.png"/>
<img src="images/1004.png"/>
</div>
</body>
</html>
<script src="../vendor/aruco-marker.js"></script>
<script src="../threex-arucomarkergenerator.js"></script>
<body style='background-color: #aaa;'><script>
var domElement = THREEx.ArucoMarkerGenerator.createImage(1001, 256)
document.body.appendChild(domElement)
var domElement = THREEx.ArucoMarkerGenerator.createImage(1002, 256)
document.body.appendChild(domElement)
var domElement = THREEx.ArucoMarkerGenerator.createImage(1003, 256)
document.body.appendChild(domElement)
var domElement = THREEx.ArucoMarkerGenerator.createImage(1004, 256)
document.body.appendChild(domElement)
</script></body>
<html>
<!-- <script src='vendor/Three.js'></script> -->
<script src='../../vendor/three.js/build/three.js'></script>
<script src='../vendor/js-aruco/src/svd.js'></script>
<script src='../vendor/js-aruco/src/posit1.js'></script>
<script src='../vendor/js-aruco/src/cv.js'></script>
<script src='../vendor/js-aruco/src/aruco.js'></script>
<script src='../threex-arucocontext.js'></script>
<script src='../threex-arucodebug.js'></script>
<!-- <script src='../build/threex-aruco-min.js'></script> -->
<!-- <script src='../build/threex-aruco-prepacked.js'></script> -->
<body style='background-color: darkgray;'>
<div id='webGLContainer' style='display: inline;'></div>
<script>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var videoElement = document.createElement('video')
// videoElement.width = 320
// videoElement.height = 240
videoElement.autoplay = true
//////////////////////////////////////////////////////////////////////////////
// Code Separator
//////////////////////////////////////////////////////////////////////////////
navigator.getUserMedia({video:true}, function (stream){
if (window.URL) {
videoElement.src = window.URL.createObjectURL(stream);
} else if (videoElement.mozSrcObject !== undefined) {
videoElement.mozSrcObject = stream;
} else {
videoElement.src = stream;
}
},
function(error){
}
);
var markerSize = 1.0; //millimeters
var arucoContext = new THREEx.ArucoContext(markerSize)
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff, 1);
renderer.setSize(arucoContext.canvas.width, arucoContext.canvas.height);
document.getElementById('webGLContainer').appendChild(renderer.domElement);
var sceneOrtho = new THREE.Scene();
var cameraOrtho = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
sceneOrtho.add(cameraOrtho);
var scenePersp = new THREE.Scene();
var cameraPersp = new THREE.PerspectiveCamera(42, arucoContext.canvas.width / arucoContext.canvas.height, 0.01, 100);
scenePersp.add(cameraPersp);
//////////////////////////////////////////////////////////////////////////////
// Code Separator
//////////////////////////////////////////////////////////////////////////////
var videoTexture = new THREE.Texture(videoElement)
videoTexture.minFilter = THREE.LinearFilter
var geometry = new THREE.PlaneGeometry(1.0, 1.0)
var material = new THREE.MeshBasicMaterial({
map: videoTexture,
depthTest: false,
depthWrite: false
})
var videoMesh = new THREE.Mesh(geometry, material);
videoMesh.position.z = -1;
sceneOrtho.add(videoMesh);
var geometry = new THREE.PlaneGeometry(1.0, 1.0, 10, 10)
var material = new THREE.MeshBasicMaterial( {
color: 'hotpink',
wireframe: true
} )
var model = new THREE.Mesh(geometry, material);
var arWorldRoot = new THREE.Group
arWorldRoot.add(model)
scenePersp.add(arWorldRoot);
//////////////////////////////////////////////////////////////////////////////
// render loop
//////////////////////////////////////////////////////////////////////////////
var lastDetectionAt = null
requestAnimationFrame(function onAnimationFrame(){
// update videoMesh
videoMesh.material.map.needsUpdate = true;
var present = Date.now()/1000
if( lastDetectionAt === null || present-lastDetectionAt >= 1/30){
lastDetectionAt = Date.now()/1000
// if( videoElement.readyState >= videoElement.HAVE_CURRENT_DATA ){
// detect markers in imageData
// console.time('detect');
var detectedMarkers = arucoContext.detect(videoElement)
// console.timeEnd('detect');
if( detectedMarkers.length > 0 ){
var detectedMarker = detectedMarkers[0]
THREEx.ArucoContext.updateObject3D(arWorldRoot, detectedMarker);
arWorldRoot.visible = true
}else{
arWorldRoot.visible = false
}
}
// render scene
renderer.autoClear = false;
renderer.clear();
renderer.render(sceneOrtho, cameraOrtho);
renderer.render(scenePersp, cameraPersp);
requestAnimationFrame(onAnimationFrame);
});
</script>
<style media="screen">
img {
width: 128px;
height: 128px;
padding: 8em;
}
</style>
<br/>
<div>
<!-- <img src="images/1001.png"/> -->
<img src="images/1001.png"/>
</div>
</body>
</html>
var THREEx = THREEx || {}
THREEx.ArucoContext = function(markerSize){
this.canvas = document.createElement('canvas');
this.canvas.width = 80*4
this.canvas.height = 60*4
// experiment with imageSmoothingEnabled
var imageSmoothingEnabled = false
var context = this.canvas.getContext('2d');
context.mozImageSmoothingEnabled = imageSmoothingEnabled;
context.webkitImageSmoothingEnabled = imageSmoothingEnabled;
context.msImageSmoothingEnabled = imageSmoothingEnabled;
context.imageSmoothingEnabled = imageSmoothingEnabled;
this.detector = new AR.Detector();
this.posit = new POS.Posit(markerSize, this.canvas.width);
}
THREEx.ArucoContext.prototype.detect = function (videoElement) {
var _this = this
var canvas = this.canvas
// get imageData from videoElement
var context = canvas.getContext('2d');
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
// detect markers in imageData
var detectedMarkers = this.detector.detect(imageData);
// compute the pose for each detectedMarkers
// FIXME: i fix we should have one posit estimator per marker
detectedMarkers.forEach(function(detectedMarker){
var markerCorners = detectedMarker.corners;
// convert the corners
var poseCorners = new Array(markerCorners.length)
for (var i = 0; i < markerCorners.length; ++ i){
var markerCorner = markerCorners[i];
poseCorners[i] = {
x: markerCorner.x - (canvas.width / 2),
y: -markerCorner.y + (canvas.height/ 2)
}
}
// estimate pose from corners
detectedMarker.pose = _this.posit.pose(poseCorners);
})
return detectedMarkers
};
THREEx.ArucoContext.updateObject3D = function(object3D, detectedMarker){
var rotation = detectedMarker.pose.bestRotation
var translation = detectedMarker.pose.bestTranslation
object3D.position.x = translation[0];
object3D.position.y = translation[1];
object3D.position.z = -translation[2];
object3D.rotation.x = -Math.asin(-rotation[1][2]);
object3D.rotation.y = -Math.atan2(rotation[0][2], rotation[2][2]);
object3D.rotation.z = Math.atan2(rotation[1][0], rotation[1][1]);
object3D.scale.x = markerSize;
object3D.scale.y = markerSize;
object3D.scale.z = markerSize;
}
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册