梶研 [関節を座標に & 正面を出したい]
2024年04月28日
関節を座標に & 正面を出したい
出席率
- 3年セミナー:??%
スケジュール
短期的な予定
- [ ] mocopi と お料理センシング
- [x] シーンとランドマークを決める(~2月上旬)
- [x] SVM で動作判別する
- [ ] 機械学習を深める
- [x] 機械学習の手法を知る
- [x] 使う手法を決める
- [x] データセットを探す
- [x] LSTM してみる
- [x] 主成分分析してみる
- [x] クラスタリング
- [ ] 自己相関
- [ ] お料理センシング
- [x] お料理でどんな動作があるかを知る
- [x] レシピを決める
- [ ] センシングする
- [ ] ?
- [ ] 論文書く
- [ ] 発表
- [ ] BLEビーコンのuuidを書き換えたい
- [x] 通信内容を読み解く
- [ ] shellコマンドで通信してみる
- [ ] 実装してみる
- [ ] BookWorm
- [x] Pasori と デスクトップアプリを接続する(技術検証)
- [x] nfc読み込み機能 & 画面を作る
- [ ] API と連携させる
- [x] 管理者画面を作る
長期的な予定
- ~?月 シーン検知?をする
- ~?月 論文を書く
- ~?月 論文発表したい
進捗報告
目的
料理中の動作を mocopi を使ってセンシングする。
このデータから最終的に位置推定を行う。
- 一定の区間でどの動作をしているかを当てる (クラス分類)
- 料理の手順を元にシーン検知を補正する
- 例) 焼く動作 → 卵割る動作 はおかしい
- 位置とシーンを相補的に補正する
- 例) 冷蔵庫の前で焼く動作 はおかしい
前回
骨格を表示したら、はちゃめちゃなった
角度の単位を rad にしてみた
左肘以外は大丈夫ぽい?
blender で確認したら全然違った
原因
単位は 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 人間が再現できる骨格だが、不思議な姿勢
回転をライブラリに任せる
腕がおかしい
リファクター
ライブラリを使って回転するようにした
rot = Rotation.from_rotvec(np.array([y_rotate, x_rotate, z_rotate]))
skeleton_copy[joint]["offset"] = rot.apply(data["offset"])
正解
肩のあたりが少し違う
デフォルトの姿勢は+90度(?)された状態ぽい
→ 簡単に直せるが、動作認識では問題ない(と考えられる)ため気にしない
正面を出す
考え方
- 腰や肩の左右を通る面の直角方向を正面とする
- 全ての点に近似する平面の直角方向を正面とする
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()
簡単にできた
骨格でやってみる
おかしい
原因
- 基準面が x-z だった
- x, y, z が入れ替わってた
※基準面を骨格に合わせて座標を変換している (多分)
x-z だった場合、y軸方向で上下させて傾けている感じ?
なんか違う気がする
- お辞儀したら傾いてしまう
- 基準面によって正面が出せない方向がある
そもそも正面を出す目的は3次元を2次元平面に落とし込むとき、
なるべく大きな動作になるようにするためであり、
必ずしも正面である必要はない(と思う)
別の案
- y軸と並行な腰を通る直線($L_1$)を取る
- その直線から最も遠い点($P_1$)を取る
- Aから最も遠い点($P_2$)を取る
- $L1$ と並行で $P1$ $P2$を結ぶ直線($L2$) と重なる平面を使う
進路関係
余談
プロフィールサイト作り直した
ペンギンを愛でた
サークルで稲武野外学習してきた