Skip to content

Activate your webcam

In this section we're going to learn how to use your webcam to capture the video. We're also going to polish our work and make it presentable to users.

Change the source of data

Instead of using a video file, we're going to use your webcam. We simply need to change the source of data and instruct MARTINS.js to use your webcam. We'll do it with 1 new line of code!

ar-demo.js
async function startARSession()
{
    if(!Martins.isSupported()) {
        throw new Error(
            'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
            'Your user agent is ' + navigator.userAgent
        );
    }

    const tracker = Martins.Tracker.ImageTracker();
    await tracker.database.add([{
        name: 'my-reference-image',
        image: document.getElementById('my-reference-image')
    }]);

    const viewport = Martins.Viewport({
        container: document.getElementById('ar-viewport')
    });

    //const video = document.getElementById('my-video'); // comment this line
    //const source = Martins.Source.Video(video); // comment this line
    const source = Martins.Source.Camera();

    const session = await Martins.startSession({
        mode: 'immersive',
        viewport: viewport,
        trackers: [ tracker ],
        sources: [ source ],
        stats: true,
        gizmos: true,
    });

    return session;
}

Let's also comment (or remove) the <video> tag from the HTML file - we no longer need it:

index.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>MARTINS.js WebAR demo</title>
        <script src="martins.js"></script>
        <script src="ar-demo.js"></script>
        <style>body { background-color: #3d5afe; }</style>
    </head>
    <body>
        <div id="ar-viewport"></div>
        <img id="my-reference-image" src="my-reference-image.webp" hidden>
        <!--
        <video id="my-video" hidden muted loop playsinline autoplay oncanplay="this.muted=true;this.play()">
            <source src="my-video.webm" type="video/webm" />
            <source src="my-video.mp4" type="video/mp4" />
        </video>
        -->
    </body>
</html>

Open http://localhost:8000 and... ta-da! The web browser will ask for your permission to access the camera. Have fun. 😉

Before using a webcam

Pay attention to the following:

  1. Low-quality cameras should be avoided. A camera of a typical smartphone is probably good enough.
  2. Don't move the camera / the target image too quickly, as quick movements produce motion blur.
  3. Ensure good lighting conditions (see below).

Check your physical scene

Good lighting conditions are important for a good user experience. Even though the MARTINS.js can handle various lighting conditions, you should get your physical scene appropriately illuminated.

When developing your own WebAR experiences, ask yourself:

  • Will my users experience AR indoors? If so, make sure that the room is sufficiently illuminated.
  • Will my users experience AR outdoors? In this case, make sure that users interact with your AR experience during the day, or have that interaction happen in a place with sufficient artificial lighting.

When printing your reference images, avoid shiny materials (e.g., glossy paper). They may generate artifacts in the image and interfere with the tracking. Prefer non-reflective materials.

If you're using a screen to display the reference image, make sure to adjust the brightness. Too much brightness causes overexposure and loss of detail, leading to tracking difficulties. Not enough brightness is also undesirable, because it makes the reference image look too dark in the video. Screen reflections are also undesirable.

Use HTTPS

When distributing your WebAR experiences over the internet, make sure to use HTTPS. Web browsers will only allow access to the webcam in secure contexts.

Here is the reference image in case you need it again:

/assets/my-reference-image.webp

Reference Image

Create a scan gimmick

Let's polish our work. When the tracker is scanning the physical scene, we'll display a visual cue suggesting the user to frame the target image. I'll call that a scan gimmick.

Save the image below as scan.png:

scan.png

Scan gimmick

In order to display that scan gimmick, we need to create a HUD. A HUD is an overlay used to display 2D content in front of the augmented scene. It's part of the viewport. Modify index.html and ar-demo.js as follows:

index.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>MARTINS.js WebAR demo</title>
        <!-- <script> tags of the rendering engine of your choice -->
        <script src="martins.js"></script>
        <script src="ar-demo.js"></script>
        <style>
        body { background-color: #3d5afe; }
        #scan { width: 100%; height: 100%; object-fit: contain; opacity: 0.75; }
        </style>
    </head>
    <body>
        <div id="ar-viewport">
            <div id="ar-hud" hidden>
                <img id="scan" src="scan.png">
            </div>
        </div>
        <img id="my-reference-image" src="my-reference-image.webp" hidden>
        <!--
        <video id="my-video" hidden muted loop playsinline autoplay oncanplay="this.muted=true;this.play()">
            <source src="my-video.webm" type="video/webm" />
            <source src="my-video.mp4" type="video/mp4" />
        </video>
        -->
    </body>
</html>
ar-demo.js
async function startARSession()
{
    if(!Martins.isSupported()) {
        throw new Error(
            'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
            'Your user agent is ' + navigator.userAgent
        );
    }

    const tracker = Martins.Tracker.ImageTracker();
    await tracker.database.add([{
        name: 'my-reference-image',
        image: document.getElementById('my-reference-image')
    }]);

    const viewport = Martins.Viewport({
        container: document.getElementById('ar-viewport'),
        hudContainer: document.getElementById('ar-hud')
    });

    //const video = document.getElementById('my-video');
    //const source = Martins.Source.Video(video);
    const source = Martins.Source.Camera();

    const session = await Martins.startSession({
        mode: 'immersive',
        viewport: viewport,
        trackers: [ tracker ],
        sources: [ source ],
        stats: true,
        gizmos: true,
    });

    return session;
}

Open http://localhost:8000. Now you can see the scan gimmick being displayed... all the time?!

Configure the scan gimmick

The scan gimmick should only be displayed when the tracker is scanning the physical scene. We should hide it as soon as a target image is recognized. If the tracking is lost, then we need to display it again because we're back in scanning mode.

A simple way to know whether or not we're tracking a target image is to use events. We're going to add two event listeners to our tracker. If a targetfound event happens, we hide the scan gimmick. If a targetlost event happens, we show the scan gimmick again.

ar-demo.js
async function startARSession()
{
    if(!Martins.isSupported()) {
        throw new Error(
            'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
            'Your user agent is ' + navigator.userAgent
        );
    }

    const tracker = Martins.Tracker.ImageTracker();
    await tracker.database.add([{
        name: 'my-reference-image',
        image: document.getElementById('my-reference-image')
    }]);

    const viewport = Martins.Viewport({
        container: document.getElementById('ar-viewport'),
        hudContainer: document.getElementById('ar-hud')
    });

    //const video = document.getElementById('my-video');
    //const source = Martins.Source.Video(video);
    const source = Martins.Source.Camera();

    const session = await Martins.startSession({
        mode: 'immersive',
        viewport: viewport,
        trackers: [ tracker ],
        sources: [ source ],
        stats: true,
        gizmos: true,
    });

    const scan = document.getElementById('scan');

    tracker.addEventListener('targetfound', event => {
        scan.hidden = true;
    });

    tracker.addEventListener('targetlost', event => {
        scan.hidden = false;
    });

    return session;
}

Hide the gizmos

Let's polish our work even more by hiding the gizmos. You may just set gizmos to false in Martins.startSession() and there will be no more gizmos. Do the same to hide the stats panel.

Let me show you a different approach. Instead of getting rid of the gizmos completely, we're going to hide them partially. They will be displayed when the tracker is scanning the physical scene, but not when the physical scene is being augmented. That's easy to do with the event listeners we have just set up:

ar-demo.js
async function startARSession()
{
    if(!Martins.isSupported()) {
        throw new Error(
            'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
            'Your user agent is ' + navigator.userAgent
        );
    }

    const tracker = Martins.Tracker.ImageTracker();
    await tracker.database.add([{
        name: 'my-reference-image',
        image: document.getElementById('my-reference-image')
    }]);

    const viewport = Martins.Viewport({
        container: document.getElementById('ar-viewport'),
        hudContainer: document.getElementById('ar-hud')
    });

    //const video = document.getElementById('my-video');
    //const source = Martins.Source.Video(video);
    const source = Martins.Source.Camera();

    const session = await Martins.startSession({
        mode: 'immersive',
        viewport: viewport,
        trackers: [ tracker ],
        sources: [ source ],
        stats: true,
        gizmos: true,
    });

    const scan = document.getElementById('scan');

    tracker.addEventListener('targetfound', event => {
        scan.hidden = true;
        session.gizmos.visible = false;
    });

    tracker.addEventListener('targetlost', event => {
        scan.hidden = false;
        session.gizmos.visible = true;
    });

    return session;
}

Open http://localhost:8000 again. Enjoy your WebAR experience! 😉