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

face-api.js中detectAllFaces()无法识别人脸且forEach报错的问题

face-api.js人脸检测返回空结果且forEach报错问题

我正在使用face-api.js开发一款Web应用,功能是让用户上传图片并检测其中的人脸。但每当选择图片时,results变量为空,同时出现错误:

Uncaught (in promise) TypeError: results.forEach is not a function

我的HTML代码

<input type="file" id="user_pic" accept="image/x-png,image/gif,image/jpeg">
<img src="images/250x250.webp" id="preview" alt="">

我的JavaScript代码

document.addEventListener('DOMContentLoaded', function() {
    run()
});

async function run() {
    // load the models
    await faceapi.loadMtcnnModel('../faceapi_models')
    await faceapi.loadFaceRecognitionModel('../faceapi_models')
}


const user_pic = document.getElementById('user_pic')
const preview = document.getElementById('preview')

user_pic.addEventListener('change', () => {
    const reader = new FileReader()
    reader.onload = (e) => {
        preview.src = e.target.result
    }
    reader.readAsDataURL(user_pic.files[0]);

    detectFaces(user_pic.files[0])
})

preview.onclick = () => user_pic.click()


async function detectFaces(input) {

    let imgURL = URL.createObjectURL(input)

    const imgElement = new Image()
    imgElement.src = imgURL

    const results = faceapi.detectAllFaces(imgElement)
        .withFaceLandmarks()
        .withFaceExpressions()
    console.log(results)

    results.forEach(result => {
        const { x, y, width, height } = result.detection.box;
        ctx.strokeRect(x, y, width, height);
    });

}

问题原因及修复方案

1. 未等待异步检测结果

faceapi.detectAllFaces()及其链式调用的方法都是异步的,返回的是Promise对象,不是直接的检测结果数组。直接调用forEach会报错,因为Promise没有这个方法。

修复:在faceapi.detectAllFaces()前添加await,确保获取到实际的检测结果数组:

const results = await faceapi.detectAllFaces(imgElement)
    .withFaceLandmarks()
    .withFaceExpressions()

2. 图片未加载完成就执行检测

创建Image对象后直接设置src,此时图片还在加载中,face-api无法读取图片内容进行检测,导致results为空。

修复:等待图片加载完成后再执行检测,用Promise包装图片加载过程:

async function detectFaces(input) {
    let imgURL = URL.createObjectURL(input)

    const imgElement = new Image()
    // 等待图片加载完成
    await new Promise((resolve) => {
        imgElement.onload = resolve
        imgElement.src = imgURL
    })

    const results = await faceapi.detectAllFaces(imgElement, new faceapi.MtcnnOptions())
        .withFaceLandmarks()
        .withFaceExpressions()
    console.log(results)

    // 后续处理...
}

注意:因为加载的是MTCNN模型,检测时需要传入new faceapi.MtcnnOptions(),否则会默认使用SSD模型,未加载SSD模型会导致检测失败。

3. 缺少Canvas上下文

代码中使用了ctx.strokeRect()但没有初始化Canvas元素和上下文。需要添加Canvas来绘制人脸框,并确保它和预览图片的位置、尺寸匹配:

首先在HTML中添加Canvas:

<input type="file" id="user_pic" accept="image/x-png,image/gif,image/jpeg">
<div style="position: relative;">
    <img src="images/250x250.webp" id="preview" alt="">
    <canvas id="detectionCanvas" style="position: absolute; top: 0; left: 0;"></canvas>
</div>

然后在JavaScript中获取Canvas上下文,并调整尺寸:

const canvas = document.getElementById('detectionCanvas')
const ctx = canvas.getContext('2d')

async function detectFaces(input) {
    // ... 图片加载代码 ...

    // 调整Canvas尺寸和图片一致
    canvas.width = imgElement.width
    canvas.height = imgElement.height
    ctx.clearRect(0, 0, canvas.width, canvas.height)

    const results = await faceapi.detectAllFaces(imgElement, new faceapi.MtcnnOptions())
        .withFaceLandmarks()
        .withFaceExpressions()
    
    if (results.length === 0) {
        console.log('未检测到人脸')
        return
    }

    results.forEach(result => {
        const { x, y, width, height } = result.detection.box;
        ctx.strokeStyle = '#ff0000'
        ctx.lineWidth = 2
        ctx.strokeRect(x, y, width, height);
    });
}

4. 模型路径校验

确保../faceapi_models路径下存在MTCNN和FaceRecognition的模型文件(比如mtcnn_model-weights_manifest.json、face_recognition_model-weights_manifest.json等),路径错误会导致模型加载失败,进而检测无结果。

完整修正后的JavaScript代码

document.addEventListener('DOMContentLoaded', function() {
    run()
});

const canvas = document.getElementById('detectionCanvas')
const ctx = canvas.getContext('2d')
const user_pic = document.getElementById('user_pic')
const preview = document.getElementById('preview')

async function run() {
    try {
        // 加载模型,添加错误捕获
        await faceapi.loadMtcnnModel('../faceapi_models')
        await faceapi.loadFaceRecognitionModel('../faceapi_models')
        console.log('模型加载成功')
    } catch (err) {
        console.error('模型加载失败:', err)
    }
}

user_pic.addEventListener('change', () => {
    const file = user_pic.files[0]
    if (!file) return

    const reader = new FileReader()
    reader.onload = (e) => {
        preview.src = e.target.result
    }
    reader.readAsDataURL(file);

    detectFaces(file)
})

preview.onclick = () => user_pic.click()

async function detectFaces(input) {
    let imgURL = URL.createObjectURL(input)

    const imgElement = new Image()
    await new Promise((resolve) => {
        imgElement.onload = resolve
        imgElement.src = imgURL
    })

    // 匹配Canvas和图片尺寸
    canvas.width = imgElement.width
    canvas.height = imgElement.height
    ctx.clearRect(0, 0, canvas.width, canvas.height)

    try {
        const results = await faceapi.detectAllFaces(imgElement, new faceapi.MtcnnOptions())
            .withFaceLandmarks()
            .withFaceExpressions()
        
        console.log('检测结果:', results)

        if (results.length === 0) {
            console.log('未检测到人脸')
            return
        }

        results.forEach(result => {
            const { x, y, width, height } = result.detection.box;
            ctx.strokeStyle = '#ff0000'
            ctx.lineWidth = 2
            ctx.strokeRect(x, y, width, height);
        });
    } catch (err) {
        console.error('检测失败:', err)
    } finally {
        // 释放URL对象
        URL.revokeObjectURL(imgURL)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20