☰
ml5.js BodyPix 人体与身体部位分割指南:在浏览器中实时分割人像与 24 个身体部位
2026/10/7 2:09:17 网站建设 项目流程
  • 人工智能
  • 机器学习
  • 深度学习
  • 计算机视觉
  • NLP

【免费下载链接】ml5-library

Friendly machine learning for the web! 🤖

项目地址:https://gitcode.com/gh_mirrors/ml/ml5-library
点击查看免费下载

BodyPix 是 ml5.js 提供的人像分割(person segmentation)模型封装,它基于 TensorFlow.js 在浏览器端运行,可把图像像素划分为“人”与“背景”两大类,并进一步将人体像素细分为 24 个身体部位。本文以 docs/reference/bodypix.md 为核心脉络,结合 src/BodyPix 源码与 examples/p5js/BodyPix 示例,完整讲解初始化参数、segment()与segmentWithParts()的调用方式与返回结构、调色板定制技巧,以及模型与训练数据的来源,读完后你可以在自己的 p5.js 或原生 JavaScript 项目中直接落地人像抠图、背景替换、身体部位可视化等能力。

BodyPix 是什么:在浏览器中做像素级人像分割

按 BodyPix 开发者的原话:"BodyPix 是一个开源机器学习模型,允许在浏览器中通过 TensorFlow.js 进行人物与身体部位分割。在计算机视觉中,图像分割(image segmentation)是指将图像中的像素按语义区域分组的技术,通常用于定位物体与边界。BodyPix 模型经过训练,可以对一个人以及二十四个身体部位(如左手、右前小腿外侧、躯干背部)完成这项任务。换句话说,BodyPix 可以把图像的像素分为两类:1)代表人的像素;2)代表背景的像素;它还可以把代表人的像素进一步归类到 24 个身体部位中的任意一个。"

从 ml5.js 的实现看,这一点被封装在 src/BodyPix/index.js 中:它直接导入@tensorflow-models/body-pix包(import * as bp from '@tensorflow-models/body-pix';),模型加载后即可调用底层estimatePersonSegmentation(人像分割)与estimatePartSegmentation(身体部位分割)两个 API。也就是说,你不需要直接接触 TensorFlow.js 的底层接口,ml5.js 已经替你完成了模型加载、参数传递与结果格式转换。

快速开始:5 行代码完成第一次分割

把下面的代码放入你的 p5.js sketch 或普通 HTML 页面中,即可体验 BodyPix 的基础流程:

const bodypix = ml5.bodyPix(modelReady); function modelReady() { // 对给定的图片执行分割 bodypix.segment(img, gotResults); } function gotResults(error, result) { if (error) { console.log(error); return; } // 输出结果 console.log(result.backgroundMask); }

流程很直观:先通过ml5.bodyPix(modelReady)创建实例并传入模型就绪回调;模型就绪后在回调里调用bodypix.segment(img, gotResults)对图像执行分割;最终结果在gotResults(error, result)中接收。注意这里img可以是HTMLImageElement、HTMLVideoElement、ImageData或HTMLCanvasElement。

初始化与配置参数

构造函数签名

const bodyPix = new ml5.bodyPix(?video, ?options, ?callback);

三个参数中,video与options是可选的,callback是模型加载完成后执行的回调函数:

参数必填说明
video可选一个HTMLVideoElement,传入后可作为后续segment()/segmentWithParts()的默认输入
callback必填模型加载完成后执行的回调函数
options可选用于改变默认行为的配置对象,可用项见下文

构造函数内部的处理可参考 src/BodyPix/index.js:它把video存入this.video,用传入的options覆盖默认值生成this.config,并调用this.loadModel()异步加载模型,最后通过callCallback(src/utils/callcallback.js)把回调接入加载流程。加载完成后this.modelReady被置为true(src/BodyPix/index.js)。

options 完整配置项

文档给出的默认配置如下:

{ multiplier: 0.75, // 1.0, 0.75, 或 0.50, 0.25 outputStride: 16, // 8, 16, 或 32,默认是 16 segmentationThreshold: 0.5, // 0 - 1,默认是 0.5 palette: { /* 24 个身体部位的颜色映射,见下文 */ }, }

对照 src/BodyPix/index.js 中的DEFAULTS,还可以确认一个文档中未列出的隐藏配置项——returnTensors:

配置项取值默认值作用
multiplier1.0、0.75、0.50、0.250.75MobileNet 的宽度乘子,控制模型大小与精度之间的权衡,数值越小模型越快但精度越低
outputStride8、16、3216输出步长,影响分割结果的像素精度与计算量,8最精细
segmentationThreshold0-10.5判定像素属于“人”的置信度阈值,越低越容易把人更多地纳入分割结果
palette对象BODYPIX_PALETTE24 个身体部位各自的id与 RGBcolor映射
returnTensors布尔值false是否在结果中保留 TensorFlow 张量,用于底层调试或进一步张量运算

其中palette定义在独立的 src/BodyPix/BODYPIX_PALETTE.js 中,对应 24 个身体部位的完整颜色表。文档原样给出了这份调色板,整理成表格如下(ml5.js 默认即为这些颜色):

部位idRGB 颜色
leftFace0[110, 64, 170]
rightFace1[106, 72, 183]
rightUpperLegFront2[100, 81, 196]
rightLowerLegBack3[92, 91, 206]
rightUpperLegBack4[84, 101, 214]
leftLowerLegFront5[75, 113, 221]
leftUpperLegFront6[66, 125, 224]
leftUpperLegBack7[56, 138, 226]
leftLowerLegBack8[48, 150, 224]
rightFeet9[40, 163, 220]
rightLowerLegFront10[33, 176, 214]
leftFeet11[29, 188, 205]
torsoFront12[26, 199, 194]
torsoBack13[26, 210, 182]
rightUpperArmFront14[28, 219, 169]
rightUpperArmBack15[33, 227, 155]
rightLowerArmBack16[41, 234, 141]
leftLowerArmFront17[51, 240, 128]
leftUpperArmFront18[64, 243, 116]
leftUpperArmBack19[79, 246, 105]
leftLowerArmBack20[96, 247, 97]
rightHand21[115, 246, 91]
rightLowerArmFront22[134, 245, 88]
leftHand23[155, 243, 88]

值得注意:当在 p5.js 环境中传入调色板时,ml5.js 还支持直接用 p5 的颜色对象(p5.Color)。src/BodyPix/index.js 中的bodyPartsSpec()会先检查传入的调色板是否达到 24 个部位,再通过p5Color2RGB()把p5.Color转回[r, g, b]数组,保证内部始终以 RGB 数组工作。这一特性在 examples/p5js/BodyPix/BodyPix_Webcam_Parts/sketch.js 中被用于实现随机 HSB/RGB 调色板生成。

运行时参数覆盖

除了构造时设置options,segment()与segmentWithParts()也接受一个options参数,用于在单次调用中临时修改outputStride与segmentationThreshold(segmentWithParts()还额外支持palette)。从源码看,这些运行时选项会被写入this.config再传给底层 API(src/BodyPix/index.js):

this.config.palette = segmentationOptions.palette || this.config.palette; this.config.outputStride = segmentationOptions.outputStride || this.config.outputStride; this.config.segmentationThreshold = segmentationOptions.segmentationThreshold || this.config.segmentationThreshold;

属性(Properties)

创建实例后,你可以访问以下公开属性:

属性类型说明
.videoObject构造时传入的HTMLVideoElement,未传则为null
.modelObject已加载的 BodyPix 底层模型
.modelReadyBoolean模型是否加载完成的标志(truthy 表示已就绪)
.modelPathString模型路径
.configObject当前生效的 BodyPix 配置对象(包含multiplier、outputStride、segmentationThreshold、palette、returnTensors)

其中.config尤其有用:在 examples/p5js/BodyPix/BodyPix_Webcam_Parts/sketch.js 中可以看到,自定义调色板正是通过读取bodypix.config.palette并改写各部位的color实现的。

方法详解

.segment():人像与背景分割

允许你把人物从背景中分割出来。

bodyPix.segment(?input, ?options, callback);

输入:

  • input:HTMLImageElement、HTMLVideoElement、ImageData、HTMLCanvasElement之一。注意:视频也可以在构造函数中传入,作为默认输入。
  • options:Object,可修改outputStride与segmentationThreshold。
  • callback:Function,用于处理.segment()结果,通常用来对分割后的图像做后续处理。

输出:

返回一个对象;如果环境中存在 p5.js,掩码会是p5.Image,否则是像素数组(UInt8):

{ segmentation, raw: { personMask: null, backgroundMask: null, }, tensor: { personMask: null, backgroundMask: null, }, personMask: null, backgroundMask: null, }

内部实现:segment()的参数解析依赖 src/utils/handleArguments.js 中的handleArguments()——它支持任意顺序的可选参数组合,会自动识别图像/视频元素、配置对象与回调(src/BodyPix/index.js)。若既没有传入图像也没有在构造时传入视频,会抛出错误:"No input image provided..."。真正的工作在segmentInternal()(src/BodyPix/index.js)中完成:

  1. 等待模型就绪(await this.ready)并等待媒体可读(mediaReady);
  2. 调用底层this.model.estimatePersonSegmentation(imgToSegment, outputStride, segmentationThreshold)得到像素级分割结果segmentation;
  3. 用bp.toMaskImageData(segmentation, true)生成背景掩码、bp.toMaskImageData(segmentation, false)生成人物掩码,存入raw;
  4. 在tf.tidy中把原图与分割掩码做张量乘法,得到带 alpha 通道的人物/背景掩码张量;
  5. 通过 src/utils/generatedImageResult.js 把张量转成raw像素数组、blob与(如果存在 p5)p5.Image;
  6. 若config.returnTensors为true,同时把张量放入result.tensor,否则张量会被dispose()释放。

这也解释了为什么结果里同时出现raw、tensor与顶层personMask/backgroundMask三套字段:raw是ImageData级别的像素数据,tensor是 TensorFlow 张量(仅returnTensors: true时),顶层字段是便于直接绘制的p5.Image(p5 环境下)或像素数组。

.segmentWithParts():身体部位分割

允许你获取人物的身体部位分割结果。

bodyPix.segmentWithParts(?input, ?options, callback);

输入:

  • input:HTMLImageElement、HTMLVideoElement、ImageData、HTMLCanvasElement之一。视频同样可在构造函数中传入。
  • options:Object,可修改outputStride、segmentationThreshold与palette。
  • callback:Function,处理分割结果的回调。

输出:

{ segmentation: *ImageData*, raw: { personMask: *ImageData*, backgroundMask: *ImageData*, partMask: *ImageData* }, tensor: { personMask: *Tensor*, backgroundMask: *Tensor*, partMask: *Tensor*, }, personMask: *P5Image*, backgroundMask: *P5Image*, partMask: *P5Image*, bodyParts: *JSONObject* }

与segment()相比,这里多了partMask(身体部位着色掩码)和bodyParts(部位元数据)。在segmentWithPartsInternal()(src/BodyPix/index.js)中,底层调用的是estimatePartSegmentation,并通过bp.toColoredPartImageData(segmentation, colorsArray)结合调色板数组生成彩色部位掩码;bodyParts则来自bodyPartsSpec(),包含每个部位的id与color。

完整可运行示例

示例一:静态图片分割(p5.js)

完整代码见 examples/p5js/BodyPix/BodyPix_Image,核心逻辑如下(节选自其 sketch.js):

let bodypix; let segmentation; let img; function preload() { img = loadImage('data/harriet.jpg'); bodypix = ml5.bodyPix(); } function setup() { createCanvas(480, 560); bodypix.segment(img, gotResults); } function gotResults(err, result) { if (err) { console.log(err); return; } segmentation = result; background(0); image(segmentation.backgroundMask, 0, 0, width, height); }

这里segmentation.backgroundMask是 p5.Image,可以直接用image()绘制到画布上,实现“只保留背景、人物变黑”的视觉效果。

示例二:网络摄像头实时分割(p5.js)

见 examples/p5js/BodyPix/BodyPix_Webcam,节选自其 sketch.js:

const options = { outputStride: 8, // 8, 16, 或 32,默认是 16 segmentationThreshold: 0.3, // 0 - 1,默认是 0.5 }; function preload() { bodypix = ml5.bodyPix(options); } function setup() { createCanvas(320, 240); video = createCapture(VIDEO, videoReady); video.size(width, height); } function videoReady() { bodypix.segment(video, gotResults); } function draw() { background(0); if (segmentation) { image(segmentation.backgroundMask, 0, 0, width, height); } } function gotResults(error, result) { if (error) { console.log(error); return; } segmentation = result; bodypix.segment(video, gotResults); // 在回调中再次调用,形成连续分割循环 }

注意两个实用技巧:一是把outputStride调低到8、segmentationThreshold调低到0.3以获得更精细的实时分割;二是在gotResults回调里递归调用bodypix.segment(video, gotResults),让每一帧分割完成后立即处理下一帧,形成流畅的连续分割管线。此外视频可以只作为输入,通过隐藏原始视频元素、只绘制掩码画布实现“虚拟背景”。

示例三:身体部位实时着色(p5.js)

见 examples/p5js/BodyPix/BodyPix_Webcam_Parts,节选自其 sketch.js:

function videoReady() { bodypix.segmentWithParts(video, gotResults, options); } function gotResults(err, result) { if (err) { console.log(err); return; } segmentation = result; background(255, 0, 0); image(segmentation.partMask, 0, 0, width, height); bodypix.segmentWithParts(video, gotResults, options); }

segmentation.partMask就是 24 个身体部位按调色板着色后的彩色掩码,直接绘制即可看到身体各部位被不同颜色标注。同一示例中还演示了自定义调色板:createSimplePalette()随机为每个部位分配 RGB 颜色,createHSBPalette()用 HSB 色彩模式生成随机色,createRGBPalette()生成随机 RGB 色(见 examples/p5js/BodyPix/BodyPix_Webcam_Parts/sketch.js),都通过改写options.palette实现。

示例四:纯 JavaScript(无 p5.js)

如果不想依赖 p5.js,可以参考 examples/javascript/BodyPix/BodyPix_Image 的 sketch.js,它使用await ml5.bodyPix()与await bodypix.segment(img)的 Promise 风格调用,并把segmentation.raw.backgroundMask.data转成ImageData后绘制到<canvas>上。示例目录中还有同名的 Webcam 与 Webcam Parts 版本,以及对应的 HTML 入口 examples/javascript/BodyPix/BodyPix_Image/index.html(通过<script src="http://localhost:8080/ml5.js">引入本地构建的 ml5.js)。

所有示例在仓库中均有对应 HTML 入口与素材:图片版使用data/harriet.jpg、data/ada.jpg(见 examples/p5js/BodyPix/BodyPix_Image 与 examples/javascript/BodyPix/BodyPix_Image)。运行这些示例时,你需要先构建 ml5.js 并在本地启动一个静态服务器(参考 docs/tutorials/local-web-server.md),因为浏览器环境加载本地文件与模型资源通常需要 HTTP 服务。

模型与数据来源

该项目由 Ellen Nickles 发起。

MobileNetV1 模型传记

  • 描述:MobileNet 描述了一类为算力受限平台(如移动设备、嵌入式设备)优化而设计的机器学习模型架构,可用于图像分类、目标检测与图像分割等任务。ml5.js 使用的这个 MobileNet 模型属于卷积神经网络(CNN),经过训练可检测图像或视频中的人与 24 个身体大致区域。CNN 在图像像素中寻找模式(如水平或垂直边缘),并通过逐层计算组合出更复杂的模式(如角或圆),最终识别出它预测属于某个类别的精细模式(如左脸或右大臂前侧)——具体类别取决于模型训练数据集中图像的标注方式。
  • ml5.js 默认模型:使用基于 TensorFlow.js 创建的 MobileNet。TensorFlow 是由 Google 开发的开源机器学习平台。
  • 开发者与年份:Google 的 TensorFlow.js 团队。TensorFlow.js BodyPix 模型由纽约大学的 Dan Oved 与 Google Research 的 Tyler Zhu 及更多贡献者于 2019 年开发。
  • 用途与目标用户:TensorFlow 是一个开源机器学习平台,拥有全面而灵活的工具、库与社区资源生态。该模型以 Apache License 2.0 许可提供给 ml5.js 使用。
  • 托管位置:截至 2019 年 6 月,ml5.js 从 TensorFlow 导入 MobileNetV1,模型托管在 NPM 数据库上,这意味着你的 ml5 sketch 会自动使用 NPM 上分发的最新版本。
  • ml5.js 贡献者与年份:由 Joey Lee 于 2019 年移植到 ml5.js。

MobileNetV1 数据传记

  • 描述:根据官方文章,模型训练数据包含两部分:(1)来自 COCO 数据集的图像;(2)数字生成的“模拟数据”。
  • 来源:COCO 数据集由多个学术与商业机构的合作者共同维护,用于“大规模目标检测、分割与图像描述”,根据论文其图像来自 Flickr;Google Research 的 Per Karlsson 渲染了数据集中其余部分的模拟图像。
  • 采集者与年份:COCO 数据库始于 2014 年。
  • 采集方法:COCO 采集图像并将像素标注为分割区域的方法在论文中有详细描述。
  • 用途与目标用户:COCO 数据集旨在推进计算机视觉研究。使用混合数据集的原因正如官方文章所述:"为像素级分割任务手动标注大量训练数据(把图像像素分成 24 个身体部位区域)非常耗时。作为替代,我们在内部使用计算机图形渲染带有 ground truth 身体部位分割标注的图像。训练时,我们把渲染图像与真实 COCO 图像(带 2D 关键点与实例分割标注)混合在一起。"

源码结构与测试验证

BodyPix 模块的源码组织如下:

  • src/BodyPix/index.js:核心实现,包含BodyPix类、默认配置、参数解析、分割与部位分割两条完整管线;
  • src/BodyPix/BODYPIX_PALETTE.js:24 个身体部位的默认调色板;
  • src/BodyPix/tests/BodyPix.test.js:测试用例,验证默认配置值(multiplier: 0.75、outputStride: 16、segmentationThreshold: 0.5)、segment()对ImageData的输入支持,以及对 128x128 测试图片的分割尺寸正确性;
  • src/utils/handleArguments.js:通用参数解析器,识别图像/视频/ImageData/p5 元素/配置/回调;
  • src/utils/generatedImageResult.js:张量到raw/blob/p5.Image的结果转换;
  • src/utils/p5Utils.js:p5 环境检测与 p5 图像转换工具。

测试代码(src/BodyPix/tests/BodyPix.test.js)还提供了一种无须浏览器 UI 即可验证 BodyPix 行为的方式:直接await bodyPix()创建实例,再对随机ImageData或固定图片调用bp.segment(img)并断言返回的segmentation.width/segmentation.height。这印证了ml5.bodyPix()在没有显式回调时会返回一个 Promise(见 src/BodyPix/index.js),因此你完全可以用 async/await 风格替代回调风格编写代码。

小结

BodyPix 是 ml5.js 中最适合快速上手的人像分割模型:ml5.bodyPix()一行完成初始化,segment()与segmentWithParts()分别提供人/背景二分类分割与 24 个身体部位细分,返回结果同时覆盖raw像素数据、p5.Image与可选张量,天然适配 p5.js 绘图与纯 JavaScript 两种场景。无论是做虚拟背景、人像抠图、身体部位着色还是交互艺术装置,配合 examples/p5js/BodyPix 与 examples/javascript/BodyPix 下的四个示例都能快速起步。如果你想在运行前进一步了解模型加载与回调机制,可继续阅读 docs/tutorials/promises-and-callbacks.md。

  • 人工智能
  • 机器学习
  • 深度学习
  • 计算机视觉
  • NLP

【免费下载链接】ml5-library

Friendly machine learning for the web! 🤖

项目地址:https://gitcode.com/gh_mirrors/ml/ml5-library
点击查看免费下载

相关推荐

上一篇:Video2X终极指南:免费AI视频增强工具,轻松实现4K超分辨率与智能插帧
下一篇:codeforces-go中的几何问题:空间关系

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询