You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Face API(JS)人脸对比HTML应用报错求助:faceapi未定义等问题

人脸对比HTML应用报错排查求助

错误信息

fr-index.html:52 Uncaught (in promise) ReferenceError: faceapi is not defined at loadModels (fr-index.html:52:13) at fr-index.html:83:5 loadModels @ fr-index.html:52 (anonymous) @ fr-index.html:83 Promise.then (anonymous) @ fr-index.html:83 Understand this error index.js:2 Uncaught ReferenceError: exports is not defined at index.js:2:23

问题概述

我正在开发一款可对比摄像头实时人脸与上传人脸相似度的HTML应用,但遇到上述无法解决的错误。我认为这些错误可能与Face API库的加载方式或函数使用有关,以下是我的完整代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Camera Comparison</title>
        <style>
            video,
            canvas,
            img {
                max-width: 45%;
            }
            canvas {
                position: absolute;
            }
        </style>
    </head>
    <body>
        <h2>Camera</h2>
        <video id="video" autoplay playsinline></video>
        <canvas id="canvas"></canvas>

        <h2>Upload Image</h2>
        <input type="file" id="imageUpload" accept="image/*" />
        <img id="uploadedImage" />

        <button id="compareButton">Compare Images</button>

        <script defer src="https://cdn.jsdelivr.net/npm/face-api.js"></script>
        <script>
            const video = document.getElementById("video");
            const canvas = document.getElementById("canvas");
            const imageUpload = document.getElementById("imageUpload");
            const uploadedImage = document.getElementById("uploadedImage");
            const compareButton = document.getElementById("compareButton");
            let uploadedFaceData;

            function startVideo() {
                navigator.mediaDevices
                    .getUserMedia({ video: true })
                    .then((stream) => {
                        video.srcObject = stream;
                    })
                    .catch((err) => {
                        console.error("Error accessing the camera: ", err);
                        alert("Could not access the camera.");
                    });
            }

            async function loadModels() {
                await Promise.all([
                    faceapi.nets.ssdMobilenetv1.loadFromUri("/models"),
                    faceapi.nets.faceLandmark68Net.loadFromUri("/models"),
                    faceapi.nets.faceRecognitionNet.loadFromUri("/models"),
                ]);
            }

            imageUpload.addEventListener("change", async (e) => {
                const file = e.target.files[0];
                if (file) {
                    const img = await faceapi.bufferToImage(file);
                    uploadedImage.src = img.src;
                    uploadedFaceData = await faceapi
                        .detectSingleFace(img)
                        .withFaceLandmarks()
                        .withFaceDescriptor();
                }
            });

            compareButton.addEventListener("click", async () => {
                const capturedFaceData = await faceapi
                    .detectSingleFace(video)
                    .withFaceLandmarks()
                    .withFaceDescriptor();

                if (!uploadedFaceData || !capturedFaceData) {
                    alert("No faces detected in one or both images.");
                    return;
                }

                const faceMatcher = new faceapi.FaceMatcher(uploadedFaceData);
                const result = faceMatcher.findBestMatch(
                    capturedFaceData.descriptor
                );
                alert(result.toString());
            });

            loadModels().then(startVideo);
        </script>
    </body>
</html>

修复方案

1. 解决faceapi is not defined错误

问题出在脚本执行顺序:自定义脚本在face-api.js未加载完成时就调用了faceapi对象。即使CDN脚本加了defer,自定义脚本也没等待库加载完成就执行了loadModels()。

修复方式:
将启动逻辑改为等待DOM和库加载完成后执行,替换原代码最后一行:

document.addEventListener('DOMContentLoaded', async () => {
    await loadModels();
    startVideo();
});

或者给自定义脚本也加上defer,确保它在CDN脚本之后执行:

<script defer src="https://cdn.jsdelivr.net/npm/face-api.js"></script>
<script defer>
    // 你的自定义代码...
</script>

2. 解决exports is not defined错误

这个错误是因为项目中可能误引入了Node.js环境的模块文件(比如index.js),浏览器不支持exports对象。

修复方式:
检查项目中是否有多余的脚本标签引入了Node.js风格的模块文件,删除或修正这些引入。当前使用的CDN链接是浏览器兼容版本,无需替换。

3. 修复模型加载问题

原代码尝试从/models路径加载模型,但该路径默认不存在,会导致模型加载失败。

修复方式:

  • 本地存放模型:从face-api.js官方仓库下载预训练模型(包含ssd_mobilenetv1、face_landmark_68、face_recognition三个文件夹),放在HTML文件同级的models目录中。
  • 或使用CDN加载模型,修改loadModels函数:
async function loadModels() {
    await Promise.all([
        faceapi.nets.ssdMobilenetv1.loadFromUri("https://cdn.jsdelivr.net/npm/face-api.js/models"),
        faceapi.nets.faceLandmark68Net.loadFromUri("https://cdn.jsdelivr.net/npm/face-api.js/models"),
        faceapi.nets.faceRecognitionNet.loadFromUri("https://cdn.jsdelivr.net/npm/face-api.js/models"),
    ]);
}

4. 修正FaceMatcher用法

原代码中new faceapi.FaceMatcher(uploadedFaceData)用法错误,FaceMatcher需要接收带标签的描述符数组。

修复方式:
修改对比按钮的点击事件逻辑:

compareButton.addEventListener("click", async () => {
    const capturedFaceData = await faceapi
        .detectSingleFace(video)
        .withFaceLandmarks()
        .withFaceDescriptor();

    if (!uploadedFaceData || !capturedFaceData) {
        alert("No faces detected in one or both images.");
        return;
    }

    // 构建带标签的描述符数组
    const labeledDescriptors = [
        new faceapi.LabeledFaceDescriptors('Uploaded Face', [uploadedFaceData.descriptor])
    ];
    const faceMatcher = new faceapi.FaceMatcher(labeledDescriptors);
    const result = faceMatcher.findBestMatch(capturedFaceData.descriptor);
    alert(`相似度:${result.distance.toFixed(2)},匹配结果:${result.label}`);
});

内容的提问来源于stack exchange,提问作者T_Braun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:00:26