大佬们如果喜欢这个项目,请帮忙在 GitHub 点个 star 吧,这样可以获取到项目的最新进展。
ps: 这次实现的效果没有时间处理 UI,欢迎来一起共建;TODO:
- UI 美化
- 支持换发型;
- 显示发型和唇部识别结果
- 寻找准确率更高、推导速度更快的模型
前言
这是开源了一个《在线换口红颜色和头发颜色》的项目,纯前端实现 的续集。
上次使用 transformers.js 的皮肤分割模型,实现了“在线换口红颜色和头发颜色”,其实这个模型还没有完全挥发它的全部能力。 我们来看看如何继续利用模型的输出实现常见的功能:人物抠图和背景替换;
效果展示
体验地址
源码地址
输出分析
import { pipeline } from '@xenova/transformers';
const segmenter = await pipeline('image-segmentation', 'Xenova/face-parsing');
const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/portrait-of-woman.jpg';
const output = await segmenter(url);
console.log(output)
我们先来加载模型,看看输出的是什么
可以看到输出是一个数组,里面是模型识别出的每个皮肤部位的“mask图”(比如左眼,右眼,嘴唇,鼻子等等);
“mask图” 直译就是遮罩图。将一个原图大小,只有目标区域(比如鼻子、或者眼睛部分)露着的黑罩子,遮在原图上。其他部分都被挡住了是黑色的,只有目标区域是白色的。
"Mask图"在图像处理和计算机视觉领域中,通常指的是一种二值图像,用于表示图像中特定区域的存在与否。在这种图像中,目标区域通常被标记为白色(或值为1),而非目标区域则被标记为黑色(或值为0)。这种图像可以用来指示如何处理原图中的特定部分,比如在图像分割、目标检测、图像编辑等应用中。
例如,在面部识别或面部表情分析中,可能会使用mask图来识别和定位面部的不同部位,如眼睛、鼻子、嘴巴等。通过这种方式,算法可以专注于分析面部的特定区域,而不是整个图像。
图像处理
我们先看原图
对应的 mask 图就是这样子的
图(1) 对应的就是背景 mask 图(虽然看效果有一些瑕疵,脖子处未识别出来),可以用来实现抠图效果。
实现透明背景效果
const data: number[] = resultData.background;
for (let index of data) {
imageData.data[index * 4 + 3] = 0;
}
实现背景换色
const data: number[] = resultData.background;
for (let index of data) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
imageData.data[index * 4 + 0] = r;
imageData.data[index * 4 + 1] = g;
imageData.data[index * 4 + 2] = b;
}
实现背景图片
// 获取背景 imageData
ctx.drawImage(bgRefs.current?.[bgIndex], 0, 0, width, height);
const bgImageData = ctx.getImageData(0, 0, width, height);
const data: number[] = resultData.background;
for (let index of data) {
// 将 mask 图白色区域的像素值赋给人像
imageData.data[index * 4 + 0] = bgImageData.data[index * 4 + 0]
imageData.data[index * 4 + 1] = bgImageData.data[index * 4 + 1]
imageData.data[index * 4 + 2] = bgImageData.data[index * 4 + 2]
}
处理完图像的 imageData 以后,就可以调用 putImageData 实现渲染了
// 渲染 canvas
ctx.putImageData(imageData, 0, 0);
如果想获取更详细的代码,可以从这里获取到 GitHub