[2022年]MediaPipeで取得した座標データの統一化の方法[CSVファイル]

# MediaPipeで取得した座標データの統一化

手の座標の見本です。
![aa.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702119/71f06798-30b7-baef-2a11-b9d786e6fd4f.jpeg)


2つのポイントを決定する。具体的にはP0(WRIST)を絶対動かない基準として設定する。それとP9(MIDDLE_FINGER_MCP)からP0までの距離が1になるように大きさを揃える。(P9以外でも大丈夫です。)
※z軸はあってもなくても大丈夫です。

まず全体のソースコードです。
```normalize.py
import csv
import numpy as np
import math

with open("landmark.csv") as file_name:
    array = np.loadtxt(file_name, delimiter=",").ravel()
    #print(array)
    
x1 = array[::3]
y1 = array[1::3]
z1 = array[2::3]
    
x2 = []
y2 = []
z2 = []
for i in range(0,21):
    a = x1[i] - x1[0]
    x2.append(a)
    b = y1[i] - y1[0]
    y2.append(b)
    c = z1[i] - z1[0]
    z2.append(c)
#print(x2, y2, z2)

#k = math.sqrt((x2[1] - x2[0])**2 + (y2[1] - y2[0])**2)
k = math.sqrt((x2[1] - x2[0])**2 + (y2[1] - y2[0])**2 + (z2[1] - z2[0])**2)
print(k)

x = []
y = []
z = []
for i in range(20):
    d = x2[i] / k
    x.append(d)
    e = y2[i] / k
    y.append(e)
    f = z2[i] / k
    z.append(f)
#print(x, y, z)

"""
#xy = []
xy.extend(x)
xy.extend(y)
np.savetxt('distance.csv', xy, delimiter=',')
"""

xyz = [] 
xyz.extend(x)
xyz.extend(y)
xyz.extend(z)

np.savetxt('distance.csv', xyz, delimiter=',')
```

読込用の座標データです。
```landmark.csv
#0_x,0_y,0_z,1_x,1_y,1_z,2_x,2_y,2_z,3_x,3_y,3_z,4_x,4_y,4_z,5_x,5_y,5_z,6_x,6_y,6_z,7_x,7_y,7_z,8_x,8_y,8_z,9_x,9_y,9_z,10_x,10_y,10_z,11_x,11_y,11_z,12_x,12_y,12_z,13_x,13_y,13_z,14_x,14_y,14_z,15_x,15_y,15_z,16_x,16_y,16_z,17_x,17_y,17_z,18_x,18_y,18_z,19_x,19_y,19_z,20_x,20_y,20_z

0.451469481,0.652247429,3.88E-07,0.39776203,0.594621599,-0.000152903,0.373409241,0.51929009,-0.019663431,0.377043515,0.45223251,-0.03330189,0.396842062,0.40474093,-0.041340236,0.401626706,0.50286001,-0.103324965,0.408331186,0.379671395,-0.116982467,0.409053624,0.395460844,-0.100276023,0.411410362,0.427753359,-0.084593035,0.451683015,0.509396553,-0.106109776,0.444376409,0.365016639,-0.143135041,0.440043449,0.294116557,-0.147520944,0.442870706,0.250151962,-0.149211541,0.494813234,0.521774828,-0.095909588,0.484428912,0.393632114,-0.10612002,0.467082083,0.414141715,-0.072775304,0.458774358,0.449492723,-0.049317408,0.530400872,0.536703229,-0.083674148,0.512897849,0.439408749,-0.077969834,0.497577071,0.452368796,-0.045357663,0.494336367,0.482049167,-0.020433536
```

読み込んだ座標をx, y, z軸でそれぞれ分けます。
```
x1 = array[::3]
y1 = array[1::3]
z1 = array[2::3]

>>print(x1, y1, z1)
x1 = [0.45146948, 0.39776203, 0.37340924, 0.37704351, 0.39684206, 0.40162671, 0.40833119, 0.40905362, 0.41141036, 0.45168302, 0.44437641, 0.44004345, 0.44287071, 0.49481323, 0.48442891, 0.46708208, 0.45877436, 0.53040087, 0.51289785, 0.49757707, 0.49433637]
y1 = [0.65224743, 0.5946216, 0.51929009, 0.45223251, 0.40474093, 0.50286001, 0.3796714, 0.39546084, 0.42775336, 0.50939655, 0.36501664, 0.29411656, 0.25015196, 0.52177483, 0.39363211, 0.41414172, 0.44949272, 0.53670323, 0.43940875, 0.4523688 , 0.48204917]
z1 = [3.88000000e-07, -1.52903000e-04, -1.96634310e-02, -3.33018900e-02, -4.13402360e-02, -1.03324965e-01, -1.16982467e-01, -1.00276023e-01, -8.45930350e-02, -1.06109776e-01, -1.43135041e-01, -1.47520944e-01, -1.49211541e-01, -9.59095880e-02, -1.06120020e-01, -7.27753040e-02, -4.93174080e-02, -8.36741480e-02, -7.79698340e-02, -4.53576630e-02, -2.04335360e-02]
```

以下の配列は、それぞれの点(P1～20)のxyz座標の値を点0の座標で引いたものを表します。
```
x2 = []
y2 = []
z2 = []

>>print(x2, y2, z2)
x2 = [0.0, -0.05370745100000002, -0.07806024, -0.07442596600000001, -0.05462741900000001, -0.049842775000000006, -0.04313829499999999, -0.042415857, -0.04005911900000003, 0.0002135340000000152, -0.007093071999999978, -0.01142603200000003, -0.008598775000000003, 0.043343752999999985, 0.032959430999999983, 0.015612601999999975, 0.007304876999999987, 0.07893139099999996, 0.06142836800000001, 0.046107589999999976, 0.04286688599999999]
y2 = [0.0, -0.05762582999999999, -0.13295733899999995, -0.200014919, -0.247506499, -0.14938741899999997, -0.27257603399999997, -0.256786585, -0.22449407, -0.14285087600000002, -0.28723079, -0.358130872, -0.402095467, -0.13047260100000002, -0.258615315, -0.23810571399999997, -0.202754706, -0.11554419999999999, -0.21283868, -0.19987863299999997, -0.170198262]
z2 = [0.0, -0.000153291, -0.019663819, -0.033302278, -0.041340624, -0.10332535300000001, -0.11698285500000001, -0.10027641100000001, -0.084593423, -0.106110164, -0.14313542899999998, -0.14752133199999998, -0.149211929, -0.09590997600000001, -0.106120408, -0.072775692, -0.049317796, -0.08367453600000001, -0.077970222, -0.045358050999999996, -0.020433924]
```

以下でP0からP9の距離を求める。
```
k = math.sqrt((x2[9] - x2[0])**2 + (y2[9] - y2[0])**2 + (z2[9] - z2[0])**2)

>>print(k)
k = 0.177948827686061
```

次に手のサイズを揃える。
||点9 - 点0|| =1 となるようにする。
つまりk = sqrt((x9-x0)^2 + (y9-y0)^2 + (z9-z0)^2) として、
すべての点0〜点20の座標値をkで割る。
割られた後の座標値をP0〜P20とする。
これを学習データとする。（ただしP0=(0,0,0)なのでP0は使わない）

以下でx,y,zをそれぞれ配列として表す。
```
x = []
y = []
z = []

>>print(x, y, z)
x = [-0.30181401978523403, -0.43866678423818906, -0.41824364323041796, -0.3069838655884501, -0.28009611329349754, -0.24241966390531655, -0.23835985632246176, -0.22511594777501265, 0.0011999741879543816, -0.03986017830088571, -0.06420965031676379, -0.04832161645464753, 0.24357425425958662, 0.18521859024633378, 0.08773647010220194, 0.04105043621241113, 0.44356229836619926, 0.3452024315011084, 0.2591058935288038]
y = [-0.32383371528394683, -0.747166141687455, -1.1240024539687794, -1.3908858081192494, -0.8394965054984833, -1.5317663934312689, -1.4430361151523028, -1.2615653214420415, -0.8027637937127571, -1.614120158783711, -2.0125497686998974, -2.2596129023641596, -0.7332029252262399, -1.453312833598722, -1.3380572218214797, -1.1393989420245116, -0.649311386326434, -1.1960667724964844, -1.1232365821067827]
z = [-0.0008614330422588534, -0.11050266110598433, -0.18714525087376352, -0.2323174844002542, -0.580646438324885, -0.6573960420036162, -0.5635126249716498, -0.4753806141911793, -0.5962959429392846, -0.8043628657813968, -0.8290098559135131, -0.8385103231095239, -0.5389750370775429, -0.5963535100507581, -0.40896977488602265, -0.2771459449398954, -0.4702168431680787, -0.43816091970864685, -0.2548937893539883]
```

以下でx,y,zの配列を1つの配列にまとめ、CSVファイルに出力する。
```
xyz = [] 
xyz.extend(x)
xyz.extend(y)
xyz.extend(z)
np.savetxt('distance.csv', xyz, delimiter=',')
```
出力されたCSVファイルです
```xyz.csv
-0.30181402,-0.438666784,-0.418243643,-0.306983866,-0.280096113,-0.242419664,-0.238359856,-0.225115948,0.001199974,-0.039860178,-0.06420965,-0.048321616,0.243574254,0.18521859,0.08773647,0.041050436,0.443562298,0.345202432,0.259105894,0.240894456,-0.323833715,-0.747166142,-1.124002454,-1.390885808,-0.839496505,-1.531766393,-1.443036115,-1.261565321,-0.802763794,-1.614120159,-2.012549769,-2.259612902,-0.733202925,-1.453312834,-1.338057222,-1.139398942,-0.649311386,-1.196066772,-1.123236582,-0.956444975,-0.000861433,-0.110502661,-0.187145251,-0.232317484,-0.580646438,-0.657396042,-0.563512625,-0.475380614,-0.596295943,-0.804362866,-0.829009856,-0.838510323,-0.538975037,-0.59635351,-0.408969775,-0.277145945,-0.470216843,-0.43816092,-0.254893789,-0.114830338
```


SVMに使用するときは、「点1から点20」を説明変数とし、21番目に「pose」の変数を加え、画像データに該当する手の形の値を加える。それを目的変数とする。
|poseの値|手の形|
|---|---|
|0|手を挙げている|
|1|goodのポーズ|
|2|中指立てる|
|3|口に人差し指をあてるポーズ|

***
>他の記事
・[[2022年]SVMの学習セットのフォーマット(CSVファイル)](https://qiita.com/netineti512/items/2596d4fbdebd700a7aa0)
・[[2022年]MediaPipeで取得した座標データの統一化の方法[CSVファイル]](https://qiita.com/netineti512/items/fd5929361a6fdb8f629b)
・[[2022年]PythonのMediaPipeを使い、動画ファイルの手を認識し、CSVファイルに座標データを保存する方法](https://qiita.com/netineti512/items/b79ff4f878c7795b6b91)
・[[2022年]PythonのOpenCVを使って動画を録画する方法](https://qiita.com/netineti512/items/57b532d5acd29ab36e67)