佐藤さとる

佐藤さとる

梶研 [関節を座標に & 正面を出したい]

2024年04月28日

関節を座標に & 正面を出したい

出席率

スケジュール

短期的な予定

長期的な予定

進捗報告

目的

料理中の動作を mocopi を使ってセンシングする。

このデータから最終的に位置推定を行う。

前回

骨格を表示したら、はちゃめちゃなった

角度の単位を rad にしてみた

image.png (70.7 kB)

左肘以外は大丈夫ぽい?

blender で確認したら全然違った

スクリーンショット 2024-04-23 11.17.12.png (727.2 kB)

原因

単位は deg(度数法, はちゃめちゃな方) であってた

ベクトルの回転方法が正しくなかった

回転させる関数が、ベクトルのスタート位置(親関節)を考慮していなかった

例)

腰(ROOT) の座標が 0, 0, 0, つま先が 0, -90, 0 としたとき、

つま先を45度曲げても 0, -88, 2(適当) 程度のはずが、

この関数は 76.58131721, -47.27897899, 0 になってしまう

def rotate(vec, roll, pitch, yaw):
    r_x = np.array(
        [[1, 0, 0], [0, np.cos(roll), -np.sin(roll)], [0, np.sin(roll), np.cos(roll)]]
    )
    r_y = np.array(
        [
            [np.cos(pitch), 0, np.sin(pitch)],
            [0, 1, 0],
            [-np.sin(pitch), 0, np.cos(pitch)],
        ]
    )
    r_z = np.array(
        [[np.cos(yaw), -np.sin(yaw), 0], [np.sin(yaw), np.cos(yaw), 0], [0, 0, 1]]
    )

    vec = np.dot(r_x, vec)
    vec = np.dot(r_y, vec)
    vec = np.dot(r_z, vec)

    return vec

修正後

def rotate(origin, end, roll, pitch, yaw):
    vec = np.array(end) - np.array(origin)

    ...

    return vec + origin

人間が再現できる骨格だが、不思議な姿勢

image.png (65.2 kB)

回転をライブラリに任せる

image.png (64.1 kB)
image.png (71.8 kB)

腕がおかしい

リファクター

ライブラリを使って回転するようにした

rot = Rotation.from_rotvec(np.array([y_rotate, x_rotate, z_rotate]))
skeleton_copy[joint]["offset"] = rot.apply(data["offset"])
image.png (64.1 kB)
image.png (64.4 kB)

正解

スクリーンショット 2024-05-06 19.00.14.png (478.9 kB)

肩のあたりが少し違う

デフォルトの姿勢は+90度(?)された状態ぽい

→ 簡単に直せるが、動作認識では問題ない(と考えられる)ため気にしない

正面を出す

考え方

  1. 腰や肩の左右を通る面の直角方向を正面とする
  2. 全ての点に近似する平面の直角方向を正面とする

1 は簡単だが、捻る動作に弱いため 2 を使う

最小二乗法 というのを使えばいいらしい

import numpy as np

# y = w[0] + w[1]x[1] + w[2]x[2]型。
#今回はw = [1, 2, 3]とする。
X = np.random.random((100, 2)) * 10 # 0から1*10の範囲をとる100*2の行列
y = 1 + 2 * X[:, 0] + 3 * X[:, 1] + np.random.randn(100)
#x0とx1の座標からyを作成。randnで本来の値にノイズを加えている。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d # 3D表示に使う
from scipy import linalg # linalg.solve(A, b)  Ax = bの解を求める関数

Xtil = np.c_[np.ones(X.shape[0]), X] # Xの行列の左端に[1,1,1,...,1]^Tを加える。(7)式を確認しよう
A = np.dot(Xtil.T, Xtil) # 標準形A,bに当てはめる。
b = np.dot(Xtil.T, y)
w = linalg.solve(A, b) # (8)式をwについて解く。

xmesh, ymesh = np.meshgrid(np.linspace(0, 10, 20),
                            np.linspace(0, 10, 20))
zmesh = (w[0] + w[1] * xmesh.ravel() +
        w[2] * ymesh.ravel()).reshape(xmesh.shape)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:, 0], X[:, 1], y, color='k')
ax.plot_wireframe(xmesh, ymesh, zmesh, color='r')
plt.show()

Pythonで最小二乗法をしてみよう

image.png (92.2 kB)

簡単にできた

骨格でやってみる

image.png (75.8 kB)

おかしい

原因

  1. 基準面が x-z だった
  2. x, y, z が入れ替わってた

※基準面を骨格に合わせて座標を変換している (多分)

x-z だった場合、y軸方向で上下させて傾けている感じ?

image.png (76.0 kB)

なんか違う気がする

そもそも正面を出す目的は3次元を2次元平面に落とし込むとき、

なるべく大きな動作になるようにするためであり、

必ずしも正面である必要はない(と思う)

別の案

  1. y軸と並行な腰を通る直線($L_1$)を取る
  2. その直線から最も遠い点($P_1$)を取る
  3. Aから最も遠い点($P_2$)を取る
  4. $L1$ と並行で $P1$ $P2$を結ぶ直線($L2$) と重なる平面を使う

進路関係

余談

プロフィールサイト作り直した

prev.satooru.me satooru.me

image.png (257.1 kB)
image.png (584.7 kB)

ペンギンを愛でた

IMG_6649.JPG (1.5 MB)
IMG_6657.JPG (2.8 MB)

サークルで稲武野外学習してきた

IMG_6752.JPG (5.5 MB)
IMG_6686.JPG (4.7 MB)
IMG_6715.JPG (7.0 MB)