OpticalFlowの結果出力にHLS2RGB

IplImageに整数を出し入れする際数字化けするので、いろいろ検索してたらこんな記事が。
http://d.hatena.ne.jp/blono/20081011/1223734332
参考にさせてもらいました。プロフィール見たら…え?10代なのこの方。


で、SURF使ってみたいと言いながら、最近はオプティカルフローを求める毎日です。オプティカルフローは動画中の各ピクセルが次のフレームでどこに移動したか(Flow)を計算する話。
なかなか良い結果が出ないんですが、そもそも画像処理の結果は息もつかせぬ数値のオラオララッシュであることが多いので、結果の善し悪しすらわからない始末。


ので、


速度ベクトルのx軸と為す角度 → 色相
速度の大きさ → 輝度


と可視化するプログラム作りました。なお、簡単のため彩度は常にmax。メモ

IplImage *VisualizeFlow(IplImage *flow)
{
	int i, j;
	int a, b;
	float dst, dst_max=0.0;
	float rad, PI = 4.0*atan(1.0);

	int w = flow->width;
	int h = flow->height;

	IplImage *src = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3);
	IplImage *ret = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3);
	
	for(j=0; j<h; j++){
		for(i=0; i<w; i++){
			a = cvImageElem<IPL_DEPTH_32S>(flow, i, j, 0);
			b = cvImageElem<IPL_DEPTH_32S>(flow, i, j, 1);
			dst = sqrt((float)(a*a + b*b));

			if(dst>dst_max) dst_max = dst;
		}
	}

	for(j=0; j<h; j++){
		for(i=0; i<w; i++){
			a = cvImageElem<IPL_DEPTH_32S>(flow, i, j, 0);
			b = cvImageElem<IPL_DEPTH_32S>(flow, i, j, 1);
			dst = sqrt((float)(a*a + b*b));

			if(a==0){
				if(b>=0)	rad = PI / 2.0;
				else		rad = PI * (3.0/2.0);
			}else{
				rad = atan((float)b/(float)a);
				if(a<0)			rad += PI;
				else if(rad<0)	rad += 2.0 * PI;
			}

			cvImageElem<IPL_DEPTH_8U>(src, i, j, 0) = 255; // S(0-255)
			cvImageElem<IPL_DEPTH_8U>(src, i, j, 1) = cvRound(127.0*dst / dst_max); // L(0-255)
			cvImageElem<IPL_DEPTH_8U>(src, i, j, 2) = cvRound(rad * (90.0/PI)); // H(0-180)
		}
	}

	cvCvtColor(src, ret, CV_HLS2BGR); // HLS→RGB

	cvReleaseImage(&src);

	return ret;
}


去年は自分でHSV→RGBのプログラム書いたんだけど、OpenCVに色空間変換の関数があるので使ってみた。便利便利。一括変換しかできないけどね。


Depth8Uのとき色相だけ0-180の範囲で入力する必要があることを強くメモ。
そういえば、上のプログラムではフローの大きさの最大値を初めに求め、それを使って再度全ピクセル走査して輝度を決定してる。だから前ピクセルを2回も見てるんだけど、これってなんとかならんのかな。2度手間なのではと考えてしまう。ほかの画像処理で輝度の平均やら分散求める時も悩むことなんだけど。



IplImage *flowに中心からの相対座標を入れておくと、結果はこんなかんじ。


ちなみにこの変換処理をフローの推定失敗結果に使うと、エレクトリックパレードみたいになる笑

全然スムースが効いてないorz