Search code examples
javascriptnode.jsexpressface-api

Can't Load Models for face-api.js despite infereing the models


I'm trying to make the app for face detection. But despite loading models. I'm getting the error "SsdMobilenetv1 - load model before inference" I'm sending the Front End HTML File from the server. and on the client front end I'm trying to do the face detection. I would be very very grateful for your kind response. Regards!!!

This is my express server

Index.js

const express = require("express")
const path = require('path')
const app = express()
const hbs = require("hbs")


const publicFolder = path.join(__dirname, '../public')
const viewsPath = path.join(__dirname, "../views")

app.use(express.static(publicFolder));


app.set("view engine", "hbs");
app.set("views", viewsPath);

app.get('/', (req, res) => {
    res.render('index.hbs')
})

app.listen(7000, () => {
    console.log("Listening On port")
})

This is the script file on front end face.js

const MODEL_URL = "/weights";
Promise.all([
    faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
    faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
    faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
]).then((val) => {
    // console here gives an array of undefined
    console.log(val)
}).catch((err) => {
    console.log(err)
})

const img = document.getElementById('img')
const inputField = document.getElementById('imgUpload')
const canvas = document.getElementById('canvas')

const inputChangeListner = function (e) {
    var selectedFile = e.target.files[0];
    var reader = new FileReader();

    img.title = selectedFile.name;

    reader.onload = function (event) {
        console.log(event)
        img.src = event.target.result;
    };

    reader.readAsDataURL(selectedFile);
}
inputField.onchange = inputChangeListner


faceapi.detectSingleFace(img).then((value) => {
 console.log(value)
}).catch((err) => { console.log(err) })

Because of low reputation, i can't post the image directly but here is the link to my folder structure

https://i.sstatic.net/xswbl.png


Solution

  • I believe that only two parts in your client-side script are relevant for this issue, so let's focus on those:

    const MODEL_URL = "/weights";
    Promise.all([
        faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
        faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
        faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
    ]).then((val) => {
        // console here gives an array of undefined
        console.log(val)
    }).catch((err) => {
        console.log(err)
    })
    
    // ...
    
    faceapi.detectSingleFace(img).then((value) => {
     console.log(value)
    }).catch((err) => { console.log(err) })
    

    so, we've got a Promise.all at the top which schedules execution of 3 functions, ssdMobilenetv1 among them, which is obligatory to call prior to calling faceapi.detectSingleFace. But, the problem is, these 3 functions from within Promise.all will be executed asynchronously, while main thread will go forward and try to invoke faceapi.detectSingleFace, even though ssdMobilenetv1 is still going on.

    Simplest solution would be to put detectSingleFace to the success callback of Promise.all:

    const MODEL_URL = "/weights";
    Promise.all([
        faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
        faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
        faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
    ]).then((val) => {
        // console here gives an array of undefined
        console.log(val);
        faceapi.detectSingleFace(img).then((value) => {
         console.log(value)
        }).catch((err) => { console.log(err) });
    }).catch((err) => {
        console.log(err)
    });
    

    Because inside the callback, you can be sure that faceapi.nets.ssdMobilenetv1 is done.