ML5.hand

def setup
  createCanvas(320, 240)
  @video = createCapture(VIDEO)
  @results = []

  @video.elt.onloadeddata = proc {
    # キャンバスに対する縮小率を計算
    # (ロードが完了するまで videoサイズは不定)
    @sx = width / @video.width
    @sy = height / @video.height
    #p  @video.width,  @video.height, @sx, @sy
    ML5.hand(@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 |hands|
    hands.each do |hand|
      noFill
      stroke(255)
      rect(hand[:_box][:x], hand[:_box][:y], hand[:_box][:w], hand[:_box][:h])    
      hand[:landmarks].each_with_index do |v, i|
        if i % 4 == 0
          fill(255, 255, 255)   # 白(指先)
        else
          fill(0, 255, 0)       # 緑
        end
        stroke(0)
        ellipse(v[0], v[1], 20, 20)
      end
    end
  end
end

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

[ml5.js] Handpose (ml5@0.12.2)
[ml5.js] Handpose (ml5@1.2.1)

概要

カメラ映像からリアルタイムに手指を検出します。

書式

ML5.hand(video, results)

引数

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

戻値

なし

備考

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

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

・配列「results」には下記のようなデータ構造の検出結果がセットされます。
 (検出対象は片手のみで、同時に両手の検出はできません)

  [                                # 1つの要素(ハッシュ)を持つ配列
    {                              # (検出される手の数は1つのみ)
      handInViewConfidence: r,     # 存在確率
      boundingBox: {               # 境界領域
        topLeft:     [bx1, by2],   #   左上座標
        bottomRight: [bx2, by2],   #   右下座標
      },
      _box: {                      # 境界領域(boundingBoxの値をもとに設定)
        x: x,                      #   左上x座標
        y: y,                      #   左上y座標
        w: w,                      #   幅
        h: h                       #   高さ
      }
      landmarks: [                 # ポイント(21ヶ所)
        [ x0,  y0,  z0],           #   座標 0 (手のひら)
        [ x1,  y1,  z1],           #   座標 1 (親指1)
        [ x2,  y2,  z2],           #   座標 2 (親指2)
        [ x3,  y3,  z3],           #   座標 3 (親指3)
        [ x4,  y4,  z4],           #   座標 4 (親指4; 指先)
        [ x5,  y5,  z5],           #   座標 5 (人差し指1)
        [ x6,  y6,  z6],           #   座標 6 (人差し指2)
        [ x7,  y7,  z7],           #   座標 7 (人差し指3)
        [ x8,  y8,  z8],           #   座標 8 (人差し指4; 指先)
        [ x9,  y9,  z9],           #   座標 9 (中指1)
        [x10, y10, z10],           #   座標10 (中指2)
        [x11, y11, z11],           #   座標11 (中指3)
        [x12, y12, z12],           #   座標12 (中指4; 指先)
        [x13, y13, z13],           #   座標13 (薬指1)
        [x14, y14, z14],           #   座標14 (薬指2)
        [x15, y15, z15],           #   座標15 (薬指3)
        [x16, y16, z16],           #   座標16 (薬指4; 指先)
        [x17, y17, z17],           #   座標17 (子指1)
        [x18, y18, z18],           #   座標18 (子指2)
        [x19, y19, z19],           #   座標19 (子指3)
        [x20, y20, z20]            #   座標20 (小指4; 指先)
      ],
      annotations: {               # 指ごとのポイント
        thumb: [                   # 親指
          [ x1,  y1,  z1],
          [ x2,  y2,  z2],
          [ x3,  y3,  z3],
          [ x4,  y4,  z4]
        ],
        indexFinger: [             # 人差し指
          [ x5,  y5,  z5],
          [ x6,  y6,  z6],
          [ x7,  y7,  z7],
          [ x8,  y8,  z8]
        ],
        middleFinger: [            # 中指
          [ x9,  y9,  z9],
          [x10, y10, z10],
          [x11, y11, z11],
          [x12, y12, z12]
        ],
        ringFinger: [              # 薬指
          [x13, y13, z13],
          [x14, y14, z14],
          [x15, y15, z15],
          [x16, y16, z16]
        ],
        pinky: [                   # 子指
          [x17, y17, z17],
          [x18, y18, z18],
          [x19, y19, z19],
          [x20, y20, z20]
        ],
        palmBase: [                # 手のひら
          [ x0,  y0,  z0]
        ]
      }
    }
  ]

関連