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行目あたりです.
// 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行目を見ると,
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
)にその差分が代入されてしまっています.まずはここを直します.
// 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行目
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の方も同じ問題があるはずなのですが,こっちはカメラ運動の推定があってもう少しややこしいので,今回は未検証です.