Help us understand the problem. What is going on with this article?

Dense Trajectoryにおけるtrajectory位置情報

More than 3 years have passed since last update.

Dense trajectory はコンピュータビジョンの動作認識問題で最近よく使われる特徴記述で,密な点群を追跡し,その軌跡(dense trajectory)上の局所特徴量に基づいて高次特徴量を記述するというものです.コードは http://lear.inrialpes.fr/people/wang/dense_trajectories に公開されており,OpenCVとffmpegがあればコンパイルできます.

取り組む問題によっては,各フレームにおけるtrajecotryの位置を取得したくなるのですが,もとのコードのままだと,位置情報が特徴量ファイルに保存されないようです.

まず,先のリンク先のページを見ると,

The following element are five descriptors concatenated one by one:

Trajectory: 2x[trajectory length] (default 30 dimension)
...

とあり,11次元目〜40次元目が位置情報にあたりそうです.

また,FAQを読むと,

How can I recover the original trajectory coordinates?

In the DenseTrack.cpp file:

std::vector trajectory(trackInfo.length+1);
for(int i = 0; i <= trackInfo.length; ++i)
trajectory[i] = iTrack->point[i]*fscales[iScale];

The coordinates of a trajectory is saved in "std::vector trajectory". Here all the coordinates are mapped to the original resolution. You can output the trajectory coordinates right after that.

とあり,trajectory変数にその情報が格納されているようです.

ところが,実際に出力される特徴ベクトルの11次元目〜40次元目を見てみると(ここではx座標が格納されている11:2:40次元を見てみます)

>> x(1,11:2:40)

ans =

  Columns 1 through 10

   -0.0114   -0.0110    0.0524    0.0558    0.0888    0.0497   -0.0926   -0.0850   -0.0523    0.0031

  Columns 11 through 15

    0.0259    0.0805    0.0810    0.1490    0.0575

となっており,負の値があったり,そもそも全て1未満の数値であったりと,なにかがおかしい…

コードを読む

データの格納がされているのは,DenseTrack.cppの168行目あたりです.

DenseTrack.cpp(L168)
                // if the trajectory achieves the maximal length
                if(iTrack->index >= trackInfo.length) {
                    std::vector<Point2f> trajectory(trackInfo.length+1);
                    for(int i = 0; i <= trackInfo.length; ++i)
                        trajectory[i] = iTrack->point[i]*fscales[iScale];

                    float mean_x(0), mean_y(0), var_x(0), var_y(0), length(0);
                    if(IsValid(trajectory, mean_x, mean_y, var_x, var_y, length)) {
                        printf("%d\t%f\t%f\t%f\t%f\t%f\t%f\t", frame_num, mean_x, mean_y, var_x, var_y, length, fscales[iScale]);

                        // for spatio-temporal pyramid
                        printf("%f\t", std::min<float>(std::max<float>(mean_x/float(seqInfo.width), 0), 0.999));
                        printf("%f\t", std::min<float>(std::max<float>(mean_y/float(seqInfo.height), 0), 0.999));
                        printf("%f\t", std::min<float>(std::max<float>((frame_num - trackInfo.length/2.0 - start_frame)/float(seqInfo.length), 0), 0.999));

                        // output the trajectory
                        for (int i = 0; i < trackInfo.length; ++i)
                            printf("%f\t%f\t", trajectory[i].x,trajectory[i].y);

結論から言うと,このIsValid関数が非常に曲者で,この中でtrajectory変数の値が書き換わってしまっていました.IsValid変数はDescriptor.hの中にあります.
まずは177行目を見ると,

Descriptor.h(L177)
    float cur_max = 0;
    for(int i = 0; i < size-1; i++) {
        track[i] = track[i+1] - track[i];
        float temp = sqrt(track[i].x*track[i].x + track[i].y*track[i].y);

とあり,track[i](=main関数のtrajectory)にその差分が代入されてしまっています.まずはここを直します.

Descriptor.h(L177)
        // track[i] = track[i+1] - track[i];
        // float temp = sqrt(track[i].x*track[i].x + track[i].y*track[i].y);
        float temp = sqrt((track[i+1]-track[i]).x*(track[i+1]-track[i]).x + (track[i+1]-track[i]).y*(track[i+1]-track[i]).y);

さらに下の方を見ていくと,位置がtrajectoryの長さ(正確には移動長の総和)で正規化されています.192行目

Descriptor.h(L192)
    norm = 1./length;
    // normalize the trajectory
    for(int i = 0; i < size-1; i++)
        track[i] *= norm;

trajectory情報はIsValid関数が呼ばれた以降,どの入力にも使われないようですので,この部分をまるっとコメントアウトしても良いかと思います.あるいは,length変数は特徴ベクトルの6次元目に入っているので,以下のような掛け算によって,元の位置情報が出てきます.

>> x(1,11:2:40) * x(1, 6)

ans =

  Columns 1 through 10

   57.0000   56.5570   56.1290   58.1660   60.3354   63.7844   65.7142   62.1172   58.8169   56.7860

  Columns 11 through 15

   56.9049   57.9097   61.0352   64.1834   69.9709

たぶん,Improved trajectoryの方も同じ問題があるはずなのですが,こっちはカメラ運動の推定があってもう少しややこしいので,今回は未検証です.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away