佐藤さとる

佐藤さとる

梶研 [mocopiとaction slam(SVM)]

2024年01月30日

mocopiとaction slam(SVM)

出席率

スケジュール

短期的な予定

長期的な予定

進捗報告

mocopiとaction slam(SVM)

梶研でいろんな動作をする中で冷蔵庫を開け閉めする動作をランドマークとする(仮)

センシング

<iframe width="1139" height="641" src="https://www.youtube.com/embed/YAV4htI3wwY" title="mocopiセンシング 冷蔵庫開け閉め+他の動作" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

特徴量

HASC2010corpusを用いた被験者数と 人間行動認識率の相関 .

https://nagoya.repo.nii.ac.jp/record/13543/files/dt_hiro.pdf

認識の際には, 平均, エネルギー, エントロピー, 相関が特徴量として使用されている

>> [2. 関連研究の紹介(p.2)]

>> Bao, L. and Intille, S. S. Activity Recognition from User-Annotated Acceleration Data. Proc of PERVASIVE 2004, pp. 1-17, 2004.

認識の際には, 特徴量として, 窓幅 5.12 秒毎の平均,標準偏差,エネルギー,相関が用いられており

>> [2. 関連研究の紹介(p.3)]

>> Ravi, N., Dandekar, N., Mysore, P. and Littman, L. M. Activity Recognition From Accelerometer Data. Proc of IAAI, pp. 1541-1546, 2005.

ノルムを計 算し, 得られた波形の平均と分散を特徴量として抽出
加速度のノルムに対して, 平均, 分散, 周波数帯域毎のエネルギー, 零点交差率 の 7 つの特徴量を用いた行動認識に関する評価実験も行った
加速度の積分値を 8 つ目の特徴量とした場合の評価実験を行った

>> [4.2 特徴量]

行動認識の特徴量

窓ごとの特徴量を出す

窓幅は3秒とする

<details>

<summary>bvhから特徴量のcsvを出力する</summary>

# 窓ごとの特徴量を抽出
## データの読み込み
bvhp = BVHparser('./logs/refrigerator.bvh')
df = bvhp.get_motion_df()

# 窓ごとの特徴量を抽出する関数
def calculate_features(window):
    features = []
    
    # 中央値の計算
    median_time = window['time'].mean()
    
    # 平均、分散、相関、ゼロ交差数、エネルギー、エントロピーの計算
    for joint in columns:
        X_rotate = window[joint + '_Xrotation'].values
        Y_rotate = window[joint + '_Yrotation'].values
        Z_rotate = window[joint + '_Zrotation'].values
        
        # 平均
        mean_value = np.mean([X_rotate, Y_rotate, Z_rotate])
        # 分散
        variance_value = np.var([X_rotate, Y_rotate, Z_rotate])
        # 相関
        correlation_value = np.corrcoef([X_rotate, Y_rotate, Z_rotate])[0, 1]
        # ゼロ交差数
        zero_crossings = np.sum(np.diff(np.signbit([X_rotate, Y_rotate, Z_rotate])) != 0)
        # エネルギー
        energy_value = np.sum(np.square([X_rotate, Y_rotate, Z_rotate]))
        # エントロピー
        # entropy_value = entropy([X_rotate, Y_rotate, Z_rotate])
        
        # features.extend([mean_value, variance_value, correlation_value, zero_crossings, energy_value, entropy_value])
        features.extend([mean_value, variance_value, correlation_value, zero_crossings, energy_value])
    
    return [median_time] + features

# 窓ごとの特徴量を計算し、結果をデータフレームに格納
window_size = 3
window_stride = 1

columns = [j for j in bvhp.get_joints() if not j.startswith('_')]
windows = [df.iloc[i:i + window_size] for i in range(0, len(df), window_stride) if i + window_size <= len(df)]
# result_columns = ['time'] + [f'{joint}_{metric}' for joint in columns for metric in ['mean', 'var', 'corr', 'zero_cross', 'energy', 'entropy']]
result_columns = ['time'] + [f'{joint}_{metric}' for joint in columns for metric in ['mean', 'var', 'corr', 'zero_cross', 'energy']]
result_data = [calculate_features(window) for window in windows]
result_df = pd.DataFrame(result_data, columns=result_columns)

# ラベル情報をもとにstateカラムを追加
labels = [
    {'title': '冷蔵庫を開ける', 'num': 1, 'times': [[10, 12], [33, 35], [39, 41], [55, 57], [77.5, 79.5], [104, 106], [133, 135]]},
    {'title': '冷蔵庫を閉める', 'num': 2, 'times': [[14, 16], [36, 38], [42, 45], [58, 60], [82, 84], [106.5, 108.5], [135, 137]]},
]

result_df['state'] = 0  # 初期値として全ての行に0を設定

for label in labels:
    for time_range in label['times']:
        start_time, end_time = time_range
        result_df.loc[(result_df['time'] >= start_time) & (result_df['time'] <= end_time), 'state'] = label['num']

# 結果をCSVファイルに書き出し
result_df.to_csv('./logs/refrigerator_with_state.csv', index=False)

</details>

特徴量を学習させる

df = pd.read_csv('./logs/refrigerator_with_state.csv')

# data の 'state' 'time' 以外を取得し, NaN を 0 で埋める
data = df.drop(['state', 'time'], axis=1).fillna(0)
target = df['state']

# 学習
clf = svm.SVC(gamma="scale")
clf.fit(data, target)

正答率を出す

# 正答率
test_data = df.drop(['time', 'state'], axis=1).fillna(0)
ans = clf.predict(test_data)

# ans と df['state'] を比較し、一致した割合を出力
print(sum(ans == df['state']) / len(df['state']))
正答率: 0.9063168562098862 (約90.6%)

誤差の原因

ラベル付けが雑かった?

大まかな1s単位で付けた

背景は手動でラベル付けした結果
 青: 冷蔵庫を開ける
 黄: 冷蔵庫を閉める
0: その他
1: 冷蔵庫を開ける
2: 冷蔵庫を閉める

正解(理想)

予測

image.png (57.5 kB)

正解と予測の差

image.png (63.4 kB)

丁寧にラベル付けした結果

正答率: 0.8908906654656007(約89.1%)

下がった

image.png (56.0 kB)
image.png (64.2 kB)

原因

  1. 動作を始める瞬間 から 終える瞬間 までなるべく広めに取ったのが悪い?
    • 確実に動作している
  2. ウィンドウサイズが大きい?
    • 1回の開ける・閉めるは1~2s に対して ウィンドウは3s
  3. 特徴量はこれだけでいいのか?
  4. データが少ない?

1. 確実に動作している部分だけにした

正答率: 0.9225312464812521 (約92.3%)
image.png (39.6 kB)
image.png (50.4 kB)

2. ウィンドウサイズを変える

window_size = 1

image.png (55.1 kB)

window_size = 2

image.png (55.9 kB)

window_size = 3

image.png (56.0 kB)

window_size = 4

image.png (56.0 kB)

window_size = 5

image.png (55.9 kB)

window_size = 10

image.png (55.3 kB)

変わらない

→ 60fps だから大差ない

window_size = 30 (0.5s)

image.png (54.6 kB)

細切れの部分が減った

TODO

データを沢山取ってやってみる

進路関係

余談

プロフィールサイトをアップデートした

技術力の問題で Next.js でブログを作れなかったため HUGO で別サイトにしていた(半年前)