JS实现人脸识别效果实例页面

回到相关文章 »

效果:

无人脸图片识别

有人脸吗?

有人脸图片识别

有人脸吗?

自己上传图片测试

代码:

HTML代码:
<section>
    <h4>无人脸图片识别</h4>
    <div class="flex">
        <figure>
            <img src="./book1.png" />
        </figure>
    </div>
    <p>有人脸吗?<button>判断</button></p>
</section>  

<section>
    <h4>有人脸图片识别</h4>
    <div class="flex">
        <figure>
            <img src="./me.jpg" />
        </figure>
    </div>
    <p>有人脸吗?<button>判断</button></p>
</section>

<section>
    <h4>自己上传图片测试</h4>
    <div class="flex">
        <input type="file" accept="image/*">
        <figure></figure>
    </div>
</section>
JS代码:
// 加载人脸识别模型
Promise.all([
  faceapi.nets.tinyFaceDetector.loadFromUri('./static-html/face/models'),
  faceapi.nets.faceLandmark68Net.loadFromUri('./static-html/face/models'),
  faceapi.nets.faceRecognitionNet.loadFromUri('./static-html/face/models'),
  faceapi.nets.faceExpressionNet.loadFromUri('./static-html/face/models')
]).then(() => {
    console.log('模型加载完成');
});

// 绘制人脸识别框的方法
const drawFace = (image, result) => {
    const container = image.closest('figure');
    // 矩形框
    const box = result.alignedRect.box;
    // 插入元素
    const shape = document.createElement('s');
    shape.style.position = 'absolute';
    shape.style.border = '2px solid yellow';
    // 计算图片和原始尺寸的比例
    const scale = image.clientWidth / image.naturalWidth;
    shape.style.left = box.x * scale + 'px';
    shape.style.top = box.y * scale + 'px';
    shape.style.width = box.width * scale + 'px';
    shape.style.height = box.height * scale + 'px';
    // 显示在页面中
    container.append(shape);
}

const detect = async (img, callback = () => {}) => {
    // 检测
    const detections = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
    // 创建元素,先删除以前的元素
    img.parentElement.querySelectorAll('s').forEach(ele => ele.remove());
    // 开始根据检测结果绘制框框
    detections.forEach(detection => {
        drawFace(img, detection);
    });
    // 回调处理
    callback(detections.length);
}

// 点击按钮计算相似度
const buttons = document.querySelectorAll('button');
// face人脸检测
buttons.forEach(button => {
    const image = button.closest('section').querySelector('img');
    button.onclick = function () {
        const startTime = Date.now();
        detect(image, (length) => {
            // 没有检测结果的时候
            const span = document.createElement('span');
            span.innerHTML = `&emsp; ${length ? length + '个人脸': '没有人脸'}(${Date.now() - startTime}ms)`;
            
            button.after(span);
        });
        
        button.disabled = true;    
    };
});

// 文件选择后
const input = document.querySelector('[type="file"]');
input.onchange = function (event) {
    const file = event.target.files[0];
    // 图片元素
    const img = input.closest('section').querySelector('img') || new Image();
    img.onload = function () {
        const startTime = Date.now();
        // 透明半透明,表示正在处理
        img.style.opacity = 0.5;
        // 开始检测上传的图片
        detect(img, (length) => {
            // 没有检测结果的时候
            const p = img.parentElement.querySelector('p') || document.createElement('p');
            p.innerHTML = `${length ? length + '个人脸': '没有人脸'}(${Date.now() - startTime}ms)`;
            // p元素如果不在页面中,插入
            if (!p.isConnected) {
                img.after(p);
            }
            // 半透明还原
            img.style.opacity = '';
        });
    };
    // 文件转base64地址给图片用
    const reader = new FileReader();
    reader.addEventListener('load', () => {
        img.src = reader.result;
        // 图片插入到页面中
        if (!img.isConnected) {
            input.nextElementSibling.append(img);
        }
    }, false);
    reader.readAsDataURL(file);
}