動画に対して、1フレームごとに以下のような処理を施します。
UIImage フォーマットの image を Mat フォーマットに変換した後、cvtColor で gray scale にします。
cv::Mat mat;
UIImageToMat( image, mat );
cv::Mat mat_gray = mat.clone();
cv::cvtColor( mat_gray, mat_gray, CV_BGR2GRAY );
次に、gray scale にした mat_gray を2値化します。
cv::Mat mat_bin = mat_gray.clone();
cv::cvtColor( mat_bin, mat_bin, threshold, 255, CV_THRESH_BINARY );
gray scale は、各ピクセルの値が0(黒)~255(白)の間の値をとっていますが、ある値を境界に黒(0)と白(255)の2値のみに変換します。ここでは、”threshold” でその境界値を与えています。

上図は、x=650~960, y=360~480 あたりに横向きに走る白い直線状の飛跡と、大小様々な大きさのたくさんの白いドットが映っています。下図は、2値化の様子を詳しく見たものです。threshold は、バックグラウンドノイズ(白いドット)をできるだけ拾わないようにしながら、必要となる飛跡を拾うように選択します。

上図からわかるように、飛跡を拾うように threshold を100まで下げると、多くのバックグラウンドノイズも合わせて拾ってしまっています。このバックグラウンドノイズが時間的に変化しないという特徴を持っていれば、各ピクセル値の時間平均を差し引くことで除くことが可能です。それに関しては後程説明します。
次に、2値化で白に選ばれた領域の境界点を探します。
cv::findContours( mat_bin, contours_raw, CV_RETR_LIST, CV_CHAIN_APPROX_NONE );

上左図の例では、バックグラウンドノイズが多いため、findContours で見つかった境界点の数が膨大になってしまっています。境界点の数が80以上のもののみを図示したのが上右図で、欲しい飛跡が抽出されています。しかし、このような抽出方法では短い飛跡が拾えなくなってしまうため、いずれにせよ、バックグラウンドノイズを落とすことは重要になります。下図に、2本の飛跡をズームインしたものを載せます。

最後に、直線によるフィッティングを行い、直線らしさの判定、フィットで得られた直線の長さ等を得ます。
for( int i = 0; i < contours_raw.size(); i ++ ){
cv::Vec4f line;
cv::fitLine( contours_raw[i], line, CV_DIST_L2, 0, 0.01, 0.01 );
}
下図に、フィットで得られた直線をシアン色で合わせて表示します。
