ML5.pose

def setup
  createCanvas(320, 240)
  @video = createCapture(VIDEO)
  @results = []
  @video.elt.onloadeddata = proc {
    # キャンバスに対する縮小率を計算
    # (ロードが完了するまで videoサイズは不定)
    @sx = width / @video.width
    @sy = height / @video.height
    # p @sx, @sy
    ML5.pose(@video, @results)
    @video.hide
  }
end

def draw
  background(220)
  image(@video, 0, 0, width, height)

  scale(@sx, @sy) if @sx and @sy   # 検出座標をキャンバスサイズに一致させる
  @results.each do |bodies|
    bodies.each do |body|
      v = body[:pose]

      # 顔
      fill(255, 255, 255)
      ellipse(v[:leftEye][:x],  v[:leftEye][:y],  15, 15)
      ellipse(v[:rightEye][:x], v[:rightEye][:y], 15, 15)
      fill(0, 0, 0)
      ellipse(v[:leftEye][:x],  v[:leftEye][:y],  10, 10)
      ellipse(v[:rightEye][:x], v[:rightEye][:y], 10, 10)
      noStroke
      fill(255, 0, 0)
      ellipse(v[:nose][:x],     v[:nose][:y],     15, 15)
      ellipse(v[:leftEar][:x],  v[:leftEar][:y],  10, 10)
      ellipse(v[:rightEar][:x], v[:rightEar][:y], 10, 10)

      fill(0, 255, 0)
      # 左
      ellipse(v[:leftShoulder][:x],  v[:leftShoulder][:y],  10, 10)
      ellipse(v[:leftElbow][:x],     v[:leftElbow][:y],     10, 10)
      ellipse(v[:leftWrist][:x],     v[:leftWrist][:y],     10, 10)
      ellipse(v[:leftHip][:x],       v[:leftHip][:y],       10, 10)
      ellipse(v[:leftKnee][:x],      v[:leftKnee][:y],      10, 10)
      ellipse(v[:leftAnkle][:x],     v[:leftAnkle][:y],     10, 10)
      # 右
      ellipse(v[:rightShoulder][:x], v[:rightShoulder][:y], 10, 10)
      ellipse(v[:rightElbow][:x],    v[:rightElbow][:y],    10, 10)
      ellipse(v[:rightWrist][:x],    v[:rightWrist][:y],    10, 10)
      ellipse(v[:rightHip][:x],      v[:rightHip][:y],      10, 10)
      ellipse(v[:rightKnee][:x],     v[:rightKnee][:y],     10, 10)
      ellipse(v[:rightAnkle][:x],    v[:rightAnkle][:y],    10, 10)

      stroke(255, 255, 255)
      strokeWeight(4)
      # 肩~肱~手首(左)
      line(v[:leftShoulder][:x],   v[:leftShoulder][:y],  v[:leftElbow][:x],   v[:leftElbow][:y])
      line(v[:leftElbow][:x],      v[:leftElbow][:y],     v[:leftWrist][:x],   v[:leftWrist][:y])
      # 肩~肱~手首(右)
      line(v[:rightShoulder][:x],  v[:rightShoulder][:y], v[:rightElbow][:x],  v[:rightElbow][:y])
      line(v[:rightElbow][:x],     v[:rightElbow][:y],    v[:rightWrist][:x],  v[:rightWrist][:y])
      # 尻~膝~足首(左)
      line(v[:leftHip][:x],        v[:leftHip][:y],       v[:leftKnee][:x],    v[:leftKnee][:y])
      line(v[:leftKnee][:x],       v[:leftKnee][:y],      v[:leftAnkle][:x],   v[:leftAnkle][:y])
      # 尻~膝~足首(右)
      line(v[:rightHip][:x],       v[:rightHip][:y],      v[:rightKnee][:x],   v[:rightKnee][:y])
      line(v[:rightKnee][:x],      v[:rightKnee][:y],     v[:rightAnkle][:x],  v[:rightAnkle][:y])
      # 胴体(両肩~両尻)
      quad(v[:leftShoulder][:x],   v[:leftShoulder][:y],
           v[:rightShoulder][:x],  v[:rightShoulder][:y],
           v[:leftHip][:x],        v[:leftHip][:y],
           v[:rightHip][:x],       v[:rightHip][:y])
    end
  end
end

ml5.jsリファレンス(参考情報)

[ml5.js] PoseNet (ml5@0.12.2)
[ml5.js] BodyPose (ml5@1.2.1)

概要

カメラ映像からリアルタイムに体の姿勢を検出します。

書式

ML5.pose(video, results)

引数

引数名内容備考オプションデフォルト値
videoカメラ映像p5elementオブジェクト
(p5mediaelementオブジェクト)
results検出結果をセットする配列後述の備考の記載を参照

戻値

なし

備考

・rbCanvas/p5では、ml5.jsの旧バージョン(0.12.2)を利用しています。
 ml5.jsの最新バージョンとは仕様や挙動などが異なる場合があります。

・ML5.poseメソッドは setupメソッドで使用してください。
 その後、カメラ画像に対象が検出されるたびに
 配列「results」にデータがセットされるので、その内容を drawメソッドで処理してください。

・配列「results」には下記のようなデータ構造の検出結果がセットされます。

  [                                            # 検出された人数分の要素(ハッシュ)を持つ配列
    {                                          # 1人目
      pose: {
        keypoints: [                           # ポイント(17ヶ所)
          {
            position: { x: x0, y: y0 },        # ポイント 0
            score: r,                          # 信頼度
            part: name                         # 部位名
          },
          {
            position: { x: x1, y: y1 },        # ポイント 1
            score: r,                          # 信頼度
            part: name                         # 部位名
          },
          ...
          ...
          ...
          {
            position: { x: x16, y: y16 },      # ポイント16
            score: r,                          # 信頼度
            part: name                         # 部位名
          },
        ],
        nose:          { x: x , y: y, confidence: r },   # ポイント(鼻)
        leftEye:       { x: x , y: y, confidence: r },   # ポイント(左目)
        rightEye:      { x: x , y: y, confidence: r },   # ポイント(右目)
        leftEar:       { x: x , y: y, confidence: r },   # ポイント(左耳)
        rightEar:      { x: x , y: y, confidence: r },   # ポイント(右耳)
        leftShoulder:  { x: x , y: y, confidence: r },   # ポイント(左肩)
        rightShoulder: { x: x , y: y, confidence: r },   # ポイント(右肩)
        leftElbow:     { x: x , y: y, confidence: r },   # ポイント(左肘)
        rightElbow:    { x: x , y: y, confidence: r },   # ポイント(右肘)
        leftWrist:     { x: x , y: y, confidence: r },   # ポイント(左手首)
        rightWrist:    { x: x , y: y, confidence: r },   # ポイント(右手首)
        leftHip:       { x: x , y: y, confidence: r },   # ポイント(左尻)
        rightHip:      { x: x , y: y, confidence: r },   # ポイント(右尻)
        leftKnee:      { x: x , y: y, confidence: r },   # ポイント(左膝)
        rightKnee:     { x: x , y: y, confidence: r },   # ポイント(右膝)
        leftAnkle:     { x: x , y: y, confidence: r },   # ポイント(左足首)
        rightAnkle:    { x: x , y: y, confidence: r }    # ポイント(右足首)
      }
    },
    {                                          # 2人目
      pose: {
        ...
      }
    },
    ...
    ...
    ...
    {                                          # N人目
      pose: {
        ...
      }
    },
  ]

関連