I want to write app to capture only one face recognition with register, check-in, check-out

79 views
Skip to first unread message

Vitisan Wiriyaphibool

unread,
Oct 12, 2025, 4:00:22 AM (7 days ago) Oct 12
to DroidScript
Enclose this the attempt with the help of many AI.  If it can't be done I will cancel my 
subscription and move on to other tools.

app.LoadPlugin("FaceAPI");

var lay, frame, cam, canvas, faceApi;
var txtEmpId, txtEmpName, empId = "", empName = "";
var detecting = false;
var useFront = true; // default to front camera; toggle removed
var FRONT_IS_MIRRORED = true;
var loc, lastLat = null, lastLon = null;
var STRICT_RECOGNITION = false; // when false, always log check-in/out; recognition optional

var PROFILE_DIR = app.GetPath() + "/Attenda";
var PROFILE_FILE = PROFILE_DIR + "/employee_profile.json";
var LOG_FILE = PROFILE_DIR + "/attendance_log.json";
var MODELS_ROOT = (app.GetAppPath ? (app.GetAppPath() + "/Assets/people") : (app.GetPath() + "/Assets/people"));
var detLoopId = null;

// Single-employee recognition state
var registeredLabel = "";            // folder label used by FaceAPI (e.g. empId_empName)
var recognitionReady = false;         // true when faces are loaded for recognition
var REGISTRATION_SHOTS = 4;           // number of images to capture during registration (keeps it fast)
var REGISTRATION_MIN_REQUIRED = 4;    // minimum images required to enable recognition
var MIN_IMAGE_SIZE_BYTES = 4096;      // basic sanity check size for captured images

function OnStart() {
    lay = app.CreateLayout("Linear", "VCenter,FillXY");

    var header = app.CreateText("📸 Attenda Face/GPS Attendance", 1, 0.09, "Bold,FillX,Center");
    header.SetTextSize(20);
    header.SetBackColor("#1565C0");
    header.SetTextColor("#FFFFFF");
    lay.AddChild(header);

    frame = app.AddLayout(lay, "Frame");
    BuildCamera();

    AddEmployeeInputs();
    AddButtonBar();

    setTimeout(function(){ LoadEmployeeData(); }, 100);

    app.AddLayout(lay);

    app.ShowProgress("Loading FaceAPI…");
    // Start in detection mode (no model needed); switch to recognition after registration.
    faceApi = app.CreateFaceAPI("detection", function(){
        app.HideProgress();
        StartDetectionLoop();
    });

    loc = app.CreateLocator("GPS,Network");
    loc.SetOnChange(OnLocation);
    loc.Start();
    app.ShowPopup("Locating…");
}

function BuildCamera(){
    try{ if(cam){ cam.StopPreview(); frame.RemoveChild(cam); } }catch(e){}
    try{ if(canvas){ frame.RemoveChild(canvas); } }catch(e){}

    var flags = "VGA,UseBitmap" + (useFront ? ",Front" : ",Back");
    cam = app.AddCameraView(frame, 0.96, 0.58, flags);
    cam.SetOnReady(function(){ cam.StartPreview(); });

    canvas = app.AddImage(frame, null, 0.96, 0.58, "alias");
    canvas.SetAlpha(0.5);
    canvas.SetPaintColor("#00C853");
    canvas.SetPaintStyle("Line");
    canvas.SetLineWidth(3);
    canvas.SetAutoUpdate(false);
}

function StartDetectionLoop(){
    try{ if(detLoopId) { clearInterval(detLoopId); detLoopId = null; } }catch(e){}
    detLoopId = setInterval(function(){
        try { faceApi.IdentifyFaces(cam, onResult); }
        catch(e){ app.Debug("IdentifyFaces error: " + e); }
    }, 800);
}

function onResult(data){
    canvas.Clear();
    if(!data || !data.length){
        detecting = false;
        canvas.SetPaintColor("#FF3B30");
        canvas.DrawRectangle(0.05, 0.05, 0.95, 0.95);
        canvas.Update();
        canvas.SetPaintColor("#00C853");
        return;
    }

    detecting = true;
    canvas.SetPaintColor("#00C853");
    var f = data[0];
    var x1 = f.x / f.imageWidth;
    var y1 = f.y / f.imageHeight;
    var x2 = (f.x + f.width) / f.imageWidth;
    var y2 = (f.y + f.height) / f.imageHeight;
    if(useFront && FRONT_IS_MIRRORED){
        var nx1 = 1 - x2, nx2 = 1 - x1; x1 = nx1; x2 = nx2;
    }
    canvas.DrawRectangle(x1, y1, x2, y2);
    canvas.Update();
}

function AddEmployeeInputs(){
    var inputLayout = app.CreateLayout("Linear", "Vertical,FillX");
    inputLayout.SetPadding(0.02, 0.01, 0.02, 0.01);
    inputLayout.SetBackColor("#F5F5F5");

    var lblEmpId = app.CreateText("Employee ID:", 0.9, -1, "Left");
    lblEmpId.SetTextSize(14);
    lblEmpId.SetTextColor("#000000");
    lblEmpId.SetMargins(0, 0.005, 0, 0.002);
    inputLayout.AddChild(lblEmpId);

    txtEmpId = app.CreateTextEdit(empId, 0.9, 0.04);
    txtEmpId.SetTextSize(16);
    txtEmpId.SetTextColor("#000000");
    txtEmpId.SetBackColor("#FFFFFF");
    txtEmpId.SetMargins(0, 0, 0, 0.005);
    txtEmpId.SetOnChange(function(text){ empId = (text||"").trim(); SaveEmployeeData(); });
    inputLayout.AddChild(txtEmpId);

    var lblEmpName = app.CreateText("Employee Name:", 0.9, -1, "Left");
    lblEmpName.SetTextSize(14);
    lblEmpName.SetTextColor("#000000");
    lblEmpName.SetMargins(0, 0.005, 0, 0.002);
    inputLayout.AddChild(lblEmpName);

    txtEmpName = app.CreateTextEdit(empName, 0.9, 0.04);
    txtEmpName.SetTextSize(16);
    txtEmpName.SetTextColor("#000000");
    txtEmpName.SetBackColor("#FFFFFF");
    txtEmpName.SetMargins(0, 0, 0, 0.005);
    txtEmpName.SetOnChange(function(text){ empName = (text||"").trim(); SaveEmployeeData(); });
    inputLayout.AddChild(txtEmpName);

    lay.AddChild(inputLayout);
}

function AddButtonBar(){
    var bar = app.CreateLayout("Linear", "Horizontal,FillX,Bottom");
    bar.SetPadding(0.02, 0.016, 0.02, 0.02);
    bar.SetBackColor("#F8F9FA");

    function styleButton(btn, back, stroke){ btn.SetStyle(back, "#FFFFFF", 14, stroke, 2, 0.7); btn.SetTextSize(18); btn.SetMargins(0.005, 0, 0.005, 0); }

    var btnReg = app.CreateButton("📝 Register", 0.31, -1);
    styleButton(btnReg, "#2E7D32", "#1B5E20");
    btnReg.SetOnTouch(function(){ DoRegister(); });

    var btnIn  = app.CreateButton("✅ Check-in", 0.31, -1);
    styleButton(btnIn, "#1565C0", "#0D47A1");
    btnIn.SetOnTouch(function(){ DoAction("checkin"); });

    var btnOut = app.CreateButton("⏹️ Check-out", 0.31, -1);
    styleButton(btnOut, "#EF6C00", "#E65100");
    btnOut.SetOnTouch(function(){ DoAction("checkout"); });

    bar.AddChild(btnReg);
    bar.AddChild(btnIn);
    bar.AddChild(btnOut);
    lay.AddChild(bar);
}

function OnLocation(data){
    lastLat = data.latitude;
    lastLon = data.longitude;
}

function LoadEmployeeData(){
    try{
        if(app.FileExists(PROFILE_FILE)){
            var data = app.ReadFile(PROFILE_FILE);
            var profile = JSON.parse(data);
            empId = profile.employeeId || "";
            empName = profile.employeeName || "";
            if(txtEmpId) txtEmpId.SetText(empId);
            if(txtEmpName) txtEmpName.SetText(empName);
        }
    }catch(e){ app.Debug("LoadEmployeeData error: " + e); }
}

function SaveEmployeeData(){
    try{
        if(!app.FolderExists(PROFILE_DIR)) app.MakeFolder(PROFILE_DIR);
        var profile = { employeeId: empId, employeeName: empName, lastUpdated: new Date().toISOString() };
        app.WriteFile(PROFILE_FILE, JSON.stringify(profile, null, 2));
    }catch(e){ app.Debug("SaveEmployeeData error: " + e); }
}

function AppendAttendanceLog(entry){
    try{
        if(!app.FolderExists(PROFILE_DIR)) app.MakeFolder(PROFILE_DIR);
        var log = [];
        if(app.FileExists(LOG_FILE)){
            try{ log = JSON.parse(app.ReadFile(LOG_FILE)) || []; }catch(e){ log = []; }
        }
        log.push(entry);
        app.WriteFile(LOG_FILE, JSON.stringify(log, null, 2));
    }catch(e){ app.Debug("AppendAttendanceLog error: " + e); }
}

function DoAction(type){
    var currentEmpId = txtEmpId ? (txtEmpId.GetText()||"").trim() : "";
    var currentEmpName = txtEmpName ? (txtEmpName.GetText()||"").trim() : "";
    empId = currentEmpId; empName = currentEmpName;

    if(!empId || !empName){
        app.Alert("Please enter both Employee ID and Employee Name.", "Missing Information");
        return;
    }

    // For check-in/out, verify recognition against the registered label.
    if(type === "checkin" || type === "checkout"){
        // Only attempt recognition when a face is currently detected
        if(!detecting){
            var entryNoFace = {
                ts: new Date().toISOString(),
                action: type,
                employee: { id: empId, name: empName },
                recognized: false,
                faceDetected: false,
                gps: { lat: lastLat, lon: lastLon }
            };
            AppendAttendanceLog(entryNoFace);
            app.Alert(JSON.stringify(entryNoFace, null, 2), "Recorded (no face)");
            return;
        }
        if(STRICT_RECOGNITION){
            if(!recognitionReady){
                // No errors: show info and do not log
                app.Alert("Recognition required. Please register first.");
                return;
            }
            VerifyEmployee(function(ok){
                if(!ok){ app.Alert("Face not recognized as registered employee."); return; }
                var entryStrict = {
                    ts: new Date().toISOString(),
                    action: type,
                    employee: { id: empId, name: empName },
                    recognized: true,
                    faceDetected: !!detecting,
                    gps: { lat: lastLat, lon: lastLon }
                };
                AppendAttendanceLog(entryStrict);
                app.Alert(JSON.stringify(entryStrict, null, 2), "Recorded");
            });
        } else {
            if(!recognitionReady){
                var entryNoRec = {
                    ts: new Date().toISOString(),
                    action: type,
                    employee: { id: empId, name: empName },
                    recognized: false,
                    faceDetected: !!detecting,
                    gps: { lat: lastLat, lon: lastLon }
                };
                AppendAttendanceLog(entryNoRec);
                app.Alert(JSON.stringify(entryNoRec, null, 2), "Recorded (no recognition)");
                return;
            }
            VerifyEmployee(function(ok){
                var entry = {
                    ts: new Date().toISOString(),
                    action: type,
                    employee: { id: empId, name: empName },
                    recognized: !!ok,
                    faceDetected: !!detecting,
                    gps: { lat: lastLat, lon: lastLon }
                };
                AppendAttendanceLog(entry);
                app.Alert(JSON.stringify(entry, null, 2), ok ? "Recorded" : "Recorded (not recognized)");
            });
        }
        return;
    }
}

// -------- Registration & Recognition Setup ---------
function DoRegister(){
    var id = txtEmpId ? (txtEmpId.GetText()||"").trim() : "";
    var name = txtEmpName ? (txtEmpName.GetText()||"").trim() : "";
    if(!id || !name){ app.Alert("Enter Employee ID and Name before registering."); return; }
    empId = id; empName = name;
    SaveEmployeeData();

    registeredLabel = (empId + "_" + empName).replace(/\s+/g, "_");
    EnsureModelsFolder(registeredLabel);
    app.Debug("Capture dir: " + (MODELS_ROOT + "/" + registeredLabel));
    app.ShowProgress("Capturing multiple face images ("+REGISTRATION_SHOTS+") for robustness…");
    CaptureEmployeeFaces(registeredLabel, REGISTRATION_SHOTS, function(){
        app.HideProgress();
        var saved = CountSavedShots(registeredLabel);
        app.Debug("Saved shots count for '"+registeredLabel+"': " + saved);
        try{
            var labelDir = MODELS_ROOT + "/" + registeredLabel;
            var files = app.ListFolder(labelDir) || [];
            app.Debug("Files under: " + labelDir + " => " + JSON.stringify(files));
            if(files.length){
                app.Alert("Saved to:\n" + labelDir + "\nFiles: " + files.join(", "));
            } else {
                app.Alert("No files found under:\n" + labelDir + "\nCapture may have failed. Check storage permission.");
            }
        }catch(eList){ app.Debug("List saved files error: " + eList); }

        // Verify image sizes to avoid zero-byte or tiny invalid files
        var validCount = VerifyImageFiles(registeredLabel);
        app.Debug("Valid image files (>"+MIN_IMAGE_SIZE_BYTES+" bytes): " + validCount);

        if(validCount >= REGISTRATION_MIN_REQUIRED){
            // Longer delay to allow filesystem to flush completely
            setTimeout(function(){
                InitRecognition(function(ok){
                    recognitionReady = !!ok;
                    if(recognitionReady) app.Alert("Registration complete. Recognition enabled for: " + empName + " ("+validCount+" images)");
                    else app.Alert("Registration saved, but recognition not ready. Try capturing more images.");
                });
            }, 1500);
        } else {
            recognitionReady = false;
            app.Alert("Captured only " + validCount + " valid image(s). Need at least " + REGISTRATION_MIN_REQUIRED + ". Please register again under steady light and varied angles.");
        }
    });
}

function EnsureModelsFolder(label){
    try{
        var appRoot = app.GetAppPath ? app.GetAppPath() : app.GetPath();
        var assetsDir = appRoot + "/Assets";
        var peopleDir = assetsDir + "/people";
        // Ensure Assets and Assets/people exist
        if(!app.FolderExists(assetsDir)) app.MakeFolder(assetsDir);
        if(!app.FolderExists(peopleDir)) app.MakeFolder(peopleDir);

        var dir = MODELS_ROOT + "/" + label;
        if(!app.FolderExists(MODELS_ROOT)) app.MakeFolder(MODELS_ROOT);
        if(!app.FolderExists(dir)) app.MakeFolder(dir);
    }catch(e){ app.Debug("EnsureModelsFolder error: " + e); }
}

function CaptureEmployeeFaces(label, shots, done){
    var dir = MODELS_ROOT + "/" + label;
    var i = 1;
    var start = Date.now();
    var maxMs = Math.max(7000, shots * 3000); // safety timeout to avoid endless spinning

    function snap(){
        if(i > shots){ if(done) done(); return; }

        // Only capture when a face is actively detected to improve image quality
        if(!detecting){
            if(Date.now() - start > maxMs){ if(done) done(); return; }
            setTimeout(snap, 300);
            return;
        }
        var path = dir + "/shot"+i+".jpg";
        try{
            // Many DroidScript builds don't support a callback for TakePicture; pace with a timer.
            if(typeof cam.TakePicture === "function"){
                cam.TakePicture(path);
            } else {
                // Fallback: trigger a detection so user sees the face box, even if no file saved.
                try{ faceApi.IdentifyFaces(cam, function(){}); }catch(e2){ app.Debug("IdentifyFaces fallback error: " + e2); }
            }
        }catch(e){ app.Debug("TakePicture error: " + e); }

        i++;

        // Stop if we've been trying for too long.
        if(Date.now() - start > maxMs){ if(done) done(); return; }
        setTimeout(snap, 1200);
    }

    // Optional: if the environment supports picture event, use it to pace, otherwise the timer handles it.
    try{
        if(typeof cam.SetOnPicture === "function"){
            cam.SetOnPicture(function(){ /* event received; timer already pacing next snap */ });
        }
    }catch(e){ /* ignore */ }

    snap();
}

function VerifyImageFiles(label){
    try{
        var dir = MODELS_ROOT + "/" + label;
        var files = app.ListFolder(dir) || [];
        var good = 0;
        for(var j=0;j<files.length;j++){
            var f = files[j];
            var low = (f||"").toLowerCase();
            if(low.endsWith(".jpg") || low.endsWith(".jpeg") || low.endsWith(".png")){
                var size = 0;
                try{ size = app.GetFileSize(dir+"/"+f) || 0; }catch(e){ size = 0; }
                app.Debug("File '"+f+"' size="+size);
                if(size >= MIN_IMAGE_SIZE_BYTES) good++;
            }
        }
        return good;
    }catch(e){ app.Debug("VerifyImageFiles error: " + e); return 0; }
}

function CountSavedShots(label){
    try{
        var dir = MODELS_ROOT + "/" + label;
        var files = app.ListFolder(dir) || [];
        var count = 0;
        for(var j=0;j<files.length;j++){
            var f = (files[j]||"").toLowerCase();
            if(f.endsWith(".jpg") || f.endsWith(".jpeg") || f.endsWith(".png")) count++;
        }
        return count;
    }catch(e){ app.Debug("CountSavedShots error: " + e); return 0; }
}

function HasAtLeastOneModelImage(){
    try{
        var labels = app.ListFolder(MODELS_ROOT) || [];
        for(var i=0;i<labels.length;i++){
            var label = labels[i];
            var dir = MODELS_ROOT + "/" + label;
            if(app.FolderExists(dir)){
                var files = app.ListFolder(dir) || [];
                for(var j=0;j<files.length;j++){
                    var f = (files[j]||"").toLowerCase();
                    if(f.endsWith(".jpg") || f.endsWith(".jpeg") || f.endsWith(".png")) return true;
                }
            }
        }
    }catch(e){ app.Debug("HasAtLeastOneModelImage error: " + e); }
    return false;
}

function InitRecognition(done){
    try{
        // Debug dataset presence
        try{
            var root = MODELS_ROOT;
            var rootFiles = app.ListFolder(root) || [];
            app.Debug("Assets/people labels: " + JSON.stringify(rootFiles));
            var labelDir = MODELS_ROOT + "/" + registeredLabel;
            var labelFiles = app.ListFolder(labelDir) || [];
            app.Debug("Label '"+registeredLabel+"' files: " + JSON.stringify(labelFiles));
        }catch(eDbg){ app.Debug("Pre-init dataset debug error: " + eDbg); }

        if(!HasAtLeastOneModelImage()){
            app.Alert("No model images found in '" + MODELS_ROOT + "'. Please re-register with face visible and storage permission enabled.");
            if(done) done(false);
            return;
        }

        try{ if(detLoopId) { clearInterval(detLoopId); detLoopId = null; } }catch(e){}

        app.ShowProgress("Initializing recognition…");
        faceApi = app.CreateFaceAPI("recognition", function(){
            var ok = false;
            try{
                // Try relative Assets path first
                var r = faceApi.SetFaces("people");
                ok = (r === undefined ? true : !!r);
                // Fallbacks to absolute (implementation-dependent)
                if(!ok){
                    try{ r = faceApi.SetFaces(MODELS_ROOT); ok = (r === undefined ? true : !!r); }catch(e1){ app.Debug("SetFaces(MODELS_ROOT) error: " + e1); }
                }
                if(!ok){
                    try{ r = faceApi.SetFaces((app.GetAppPath? app.GetAppPath() : app.GetPath())+"/Assets/people"); ok = (r === undefined ? true : !!r); }catch(e2){ app.Debug("SetFaces(app Assets/people) error: " + e2); }
                }
                if(!ok){
                    try{ r = faceApi.SetFaces(app.GetPath()+"/Assets/people"); ok = (r === undefined ? true : !!r); }catch(e3){ app.Debug("SetFaces(app.GetPath Assets/people) error: " + e3); }
                }
                recognitionReady = !!ok;
            }catch(eSet){ app.Debug("SetFaces('people') error: " + eSet); ok = false; recognitionReady = false; }
            app.HideProgress();
            StartDetectionLoop();
            if(done) done(ok);
        });
    }catch(e){ app.Debug("InitRecognition error: " + e); if(done) done(false); }
}

function TestDatasetSetup(){
    try{
        app.Debug("=== DATASET TEST ===");
        app.Debug("MODELS_ROOT: " + MODELS_ROOT);
        app.Debug("Registered label: " + registeredLabel);
        var labelDir = MODELS_ROOT + "/" + registeredLabel;
        app.Debug("Full path: " + labelDir);
        app.Debug("Folder exists: " + app.FolderExists(labelDir));
        if(app.FolderExists(labelDir)){
            var files = app.ListFolder(labelDir) || [];
            app.Debug("Files found: " + files.length);
            for(var i=0;i<files.length;i++){
                var path = labelDir + "/" + files[i];
                var size = 0;
                try{ size = app.GetFileSize(path) || 0; }catch(e){ size = 0; }
                app.Debug("  - " + files[i] + ": " + size + " bytes");
            }
        }
    }catch(e){ app.Debug("TestDatasetSetup error: " + e); }
}

function VerifyEmployee(cb){
    try{
        faceApi.IdentifyFaces(cam, function(data){
            var ok = false;
            if(data && data.length){
                // Expect FaceAPI to label recognized face with folder name
                var name = data[0].name || "";
                app.Debug("Recognized name: '"+name+"' vs registeredLabel: '"+registeredLabel+"'");
                if(name === registeredLabel) ok = true;
            }
            cb(ok);
        });
    }catch(e){ app.Debug("VerifyEmployee error: " + e); cb(false); }
}

Jumar

unread,
Oct 13, 2025, 10:39:14 AM (5 days ago) Oct 13
to DroidScript
Hi 

It can be done. I already created an attendance app with facial recognition using FaceAPI plugin and successfully uploaded to Google Play. 

I don't have much time to look into the code you provided above. I search the "faceapi Train" method but I did not find one. I highly suggest when using this kind of feature e.g. attendance that requires multiple faces, use the Train() method to reduce loading time the next time you open the app. The trained models can be updated, so registering additonal faces is not a hassle. I can will create a simple working attendance SPK tommorow using FaceAPI plugin so that you have a guide.

Regards

Jumar

unread,
Oct 13, 2025, 10:45:29 AM (5 days ago) Oct 13
to DroidScript
Oh I forgot to read the title of the post about one face recognition.

Still use the Train() method. But I also suggest that you must have at least one pre-trained face model for the plugin to return the highest possible value. If you provide only one face for recognition, it has no face to compare. So if the recognition has some value, it will return that as recognize image even though the similarity value is very low. Accuracy can be achieved by passing threshold value. Read the docs for more info.

Regards

Jumar

unread,
Oct 14, 2025, 12:51:20 AM (5 days ago) Oct 14
to DroidScript
Hi.

Here's a simple working app

app.LoadPlugin("FaceAPI")

function OnStart() {
appPath = app.GetPath()
if( app.InIDE() ) appPath = app.GetAppPath()
app.ShowProgress("Initializing")
faceApi = app.CreateFaceAPI("recognition", OnFaceAPIReady)
modelsPath = appPath+"/public/models"
app.MakeFolder(appPath+"/public")
app.MakeFolder(modelsPath )
myName = "John Doe"
myModelPath = modelsPath+"/"+myName
photoCount = 0
app.MakeFolder(myModelPath)
var myFaces = app.ListFolder(myModelPath)
photoCount = myFaces.length
lay = app.CreateLayout("Linear", "VCenter,FillXY")
lay.SetChildMargins(0,4,0,4,"dp")
cam = app.AddCameraView(lay, 0.8, 0.4, "VGA,Front,UseBitmap")
cam.SetOnReady( cam_OnReady )
txtCount = app.AddText(lay, "Photo count: "+photoCount)
snapBtn = app.AddButton(lay, "Take photo")
snapBtn.SetOnTouch( TakePicture )
if( photoCount == 2 ) {
snapBtn.SetEnabled(false)
}
trainBtn = app.AddButton(lay, "Train model")
trainBtn.SetEnabled(photoCount == 2 ? true : false)
trainBtn.SetOnTouch( TrainModel )
scanBtn = app.AddButton(lay, "Scan face")
scanBtn.SetOnTouch( ScanFaces )
app.AddLayout(lay)
}

function OnFaceAPIReady() {
app.HideProgress()
}

function cam_OnReady() {
cam.StartPreview()
}

function TakePicture() {
if(photoCount == 2) {
snapBtn.SetEnabled(false)
}
photoCount++
cam.TakePicture(myModelPath+"/img-"+photoCount+".png")
txtCount.SetText("Photo count: "+photoCount)
trainBtn.SetEnabled(photoCount == 2 ? true : false)
}

function TrainModel() {
app.ShowProgress("Training a model")
faceApi.Train("models", "users")
.then(() => {
app.HideProgress()
app.ShowPopup("You can now scan a face")
})
.catch(err => {
app.HideProgress()
console.log(err)
})
}

function ScanFaces() {
if( !app.FileExists(appPath+"/public/trained_models/users.json") ) {
return
}
faceApi.SetModel("public/trained_models/users.json")
faceApi.IdentifyFaces(cam, data => {
console.log(JSON.stringify(data, null, 2))
if( data.length ) {
app.Alert( data[0].name, "Face detected")
}
})
}
Reply all
Reply to author
Forward
0 new messages