使用 p5.js 和 ml5.js 的BodyPix
來實現人形去背與物件碰撞的體感互動
今天來嘗試透過與Microsoft Bing的對話來產生體感互動的程式。
過程中遇到有些程式碼的功能本身是不存在的,Bing AI會當作假設有這個功能屬性的狀況,接下去的程式流程,所以還需要去找出真正有這個功能的套件。
基本上,透過與Microsoft Bing的對話,可以幫助到初步整體框架的程式流程,接下來的細部流程或是功能的調整,以及另外的套件的引入,仍是需要自身進行編寫的。
以下是經過修正調整後,確定可以執行的程式碼。
使用p5.js和ml5.js的BodyPix來實現人形分割與物件碰撞的體感互動
將分割後的人形接著進行輪廓路徑的偵測,以此輪廓做為畫面中物件掉落的碰撞互動。
使用ml5.js的BodyPix模型的segmentation
結果中的personMask
屬性來獲取人體的遮罩。接著使用物件位置處的人形遮罩的顏色來檢測是否產生碰撞,作為實現物件與人體輪廓的碰撞互動。
以下是一個完整的HTML文件,包括引入p5.js和ml5.js。
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/p5.collide2d@0.7.3/p5.collide2d.js"></script>
</head>
<body>
<script>
let bodypix;
let video;
let segmentation;
let particles = [];
let pg;
let st = 0;
let imgData = [];
let can;
function setup() {
can = createCanvas(320, 240);
// 加載攝像頭視頻
video = createCapture(VIDEO);
video.size(width, height);
video.hide();
// 加載BodyPix模型
bodypix = ml5.bodyPix(video, modelReady);
pg = createGraphics(width, height);
textSize(32);
}
function modelReady() {
console.log('Model Ready!');
bodypix.segment(gotResults);
}
function gotResults(err, result) {
if (err) {
console.log(err);
return;
}
segmentation = result;
// 繼續進行分割
bodypix.segment(gotResults);
}
function draw() {
background(0);
if (segmentation) {
//image(segmentation.backgroundMask, 0, 0, width, height);
image(segmentation.personMask, 0, 0, width, height);
// 繪制人體輪廓
pg.background(0);
pg.image(segmentation.personMask, 0, 0, width, height);
//pg.image(segmentation.backgroundMask, 0, 0, width, height);
// 更新物件位置
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.update();
p.display();
// 檢測物件與人體輪廓之間的碰撞
const ctx = pg.elt.getContext("2d");
ctx.getContextAttributes().willReadFrequently = true;
let imageData = ctx.getImageData(p.x, p.y, 1, 1).data;
let br = (imageData[0]+imageData[1]+imageData[2])/3;
if(br<1 && p.y>10){
p.collide();
}
// 移除超出畫面的物件
if (p.y > height + p.r || p.y < -30 || p.x > width + p.r || p.x < -p.r) {
particles.splice(i, 1);
}
}
// 隨機生成新物件
if (random(5) < 2) {
particles.push(new Particle(random(width), -20));
}
}
fill(10, 10, 0);
text(particles.length, 15, 30);
}
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.r = random(5, 15);
this.speedx = random(-5, 5);
this.speedy = random(5, 10);
this.color = color(random(255), random(255), random(255));
this.st = 0;
}
update() {
this.y += this.speedy;
this.x += this.speedx;
}
display() {
fill(this.color);
noStroke();
ellipse(this.x, this.y, this.r * 2);
}
collide() {
if(this.st==0){
this.st = 1;
this.speedx *= -0.5;
this.speedy *= -0.5;
this.y += this.speedy;
this.x += this.speedx;
}
}
}
</script>
</body>
</html>
參考來源:
1.Microsoft Bing的聊天對談
2.p5.collide2D
3.bodypix
4.HTML canvas getImageData() Method
5.bodypix demo