Translate

pythonで角度データを扱うときに符号が反転・もしくは180°ひっくりかえってしまうときに対応する関数

こんにちは。
pythonを使ったhuman pose estimationを仕事でよく使っていると、取得した
ピクセル座標から関節角度を出したりすることが多くあります。

openpose やmediapipeといった二次元のピクセル座標系による場合にはあんまり起きない現象なのですが、よくアークタンジェントとかを使った関数で角度計算をやったり、Kinectとかのクォータニオンのデータとかをオイラー角に変換する際などには、角度のデータが吹っ飛んだり、符号が飛んだりすることが多くあります。特にあるケースとしては、いきなり180°加算されたり、マイナスになったりするケースです。

これは角度計算の際に象限をまたいでしまった際に起こる現象であり、これを処理するためには、象限をまたぐフェーズを特定し、適宜180°を足し引きする必要があります。

今回は角度の時系列データ(オイラー角を含んだ3列の時系列データを想定)について象限をまたいだ際のデータ処理の関数について自作したので紹介していこうと思います。

実際のpythonコード



def euler_post_process(data,num,col):
    #オイラー角で180°付近でデータがひっくり変える時に適切に処理ための関数
    #入力変数
    #data = オイラー角の生データ
    #num = 何行目のデータか?
    #col = デーの列指定
    if data[num,col]-data[num-1,col]>90:
        data[num,col] = data[num,col]-180
    elif data[num,col]-data[num-1,col]<-90:
        data[num,col] = data[num,col]+180
    else:
        data[num,col] = data[num,col]
    return data[num,col]
今回作成した関数がこちらになります。メインで使うpythonのパッケージは特にはありません。基本的なパッケージとしてnumpyとかが入っていればこの関数は動作すると思います。

コードの中身の解説に移ります。入力する引数は主に3つで、一つ目は実際のオイラー角の時系列データです。これは【複数行、3列】のnumpy配列データを想定しています。二つ目のnumの引数ではオイラー角の配列の何行目を処理するかを指定します。このnumはforループの引数とかを入れてループ内で動作させることを想定します。最後の引数のcolは、どの列の角度データに処理を行うかを指定しています。

これら三つの引数を入れてやれば比較的綺麗に角度データの処理を行うことができます。

具体的なpython関数の内容の説明

具体的な関数の説明に移ります。この関数では指定された行の一つ前の行の値と比較して、その1フレーム当たりの差分が90°以上だった場合に象限をまたいだと判定し、その行に対して180°を加算もしくは減算する処理を与えています。そうすることによってデータが飛ぶ部分をきれいに処理することができます。

これをうまい具合に応用してやれば、外れ値で飛んでしまったデータとかのフィルタリング処理とかにも使えるかもしれませんね。

既存のフィルタリング処理でやろうとするデータが汚くなる

私もこの関数を作る前は、Hampelフィルタやローパスフィルタで何とか処理してやろうと考えてpythonコードを書いてみましたが、結果的にデータ自体に良い影響を与えなかったので、このように異常個所を特定してそこに対して処理を加えることを行うことで解決を図りました。

難しいかなと思ったのですが、意外と簡単に処理することができたので良かったし、こういったpythonコードの書き方は他にも応用が利きそうなので、これからも色々と利用していこうと思います。

これで3Dの角度データをうまく扱うことができるようになれば、Kinectのデータ解析も色々と捗るような気がしてきました。最近やっと雑多なデータ処理に目途がついてきて、pythonコードを新しく書いたりといったクリエイティブな作業ができるようになってきましたので、今後も色々と約に立ちそうなコードがあったら沢山発信していこうと思っています。

角度計算自体のコードに関しては、私の他の記事でもかいているので、そちらについても見ていただければ理解が深まると思います。

※python を使った角度計算の記事