SIFT+RANSACのサンプル

いろいろなサイト[1]を参考にしつつ、とりあえず作ってみたのだけど、精度がイマイチです。
■コード一式(VS2010用)
http://navi.cs.kumamoto-u.ac.jp/~koutaki/opencv_matching.zip


FindHomographyでRANSACを使って、斜影変換行列を求めているのだけど、
四角になるはずの検出結果がおかしい。なんかやり方がおかしいのでしょうか。
誰か教えてください。

//
//  特徴点&対応付けプログラム
//
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <nonfree/nonfree.hpp>	// ver.2.4から必要
#include <vector>
using namespace std;


// 表示用画像の作成
IplImage* stack_imgs( IplImage* img1, IplImage* img2 )
{
	IplImage* stacked = cvCreateImage( cvSize( MAX(img1->width, img2->width),
		img1->height + img2->height ),
		IPL_DEPTH_8U, 3 );

	cvZero( stacked );
	cvSetImageROI( stacked, cvRect( 0, 0, img1->width, img1->height ) );
	cvAdd( img1, stacked, stacked, NULL );
	cvSetImageROI( stacked, cvRect(0, img1->height, img2->width, img2->height) );
	cvAdd( img2, stacked, stacked, NULL );
	cvResetImageROI( stacked );

	return stacked;
}

// ホモグラフィHを使って斜影変換を行うルーチン
CvPoint persp_xform_pt( CvPoint & pt, cv::Mat & H )
{
	CvPoint ret;

	CvMat XY, UV;
	double xy[3] = { pt.x, pt.y, 1.0 }, uv[3] = { 0 };
	CvPoint2D64f rslt;

	cvInitMatHeader( &XY, 3, 1, CV_64FC1, xy, CV_AUTOSTEP );
	cvInitMatHeader( &UV, 3, 1, CV_64FC1, uv, CV_AUTOSTEP );
	CvMat T = H;
	cvMatMul( &T, &XY, &UV );
	rslt = cvPoint2D64f( uv[0] / uv[2], uv[1] / uv[2] );

	ret.x = rslt.x;
	ret.y = rslt.y;
	return ret;
}


int main (int argc, char **argv)
{

	CvMemStorage *storage = cvCreateMemStorage (0);

	if (argc == 1) {
		fprintf (stderr, "usage: %s input_imagefile\n", argv[0]);
		exit (0);
	}

	// ウインドウの設定
	cvNamedWindow ("srcimage", CV_WINDOW_AUTOSIZE);    //入力画像表示用
	cvNamedWindow ("livecapture", CV_WINDOW_AUTOSIZE); //キャプチャ画像表示用

	// キャプチャデバイスの設定
	CvCapture *cap;
	IplImage  *cap_img_rgb = 0;
	IplImage  *cap_img_gray = 0;

	cap = cvCreateCameraCapture(CV_CAP_ANY);

	if (cap == NULL) {
		fprintf (stderr, "cvCreateCameraCapture() failed...\n");
		exit (0);
	}
	cvSetCaptureProperty (cap, CV_CAP_PROP_FRAME_WIDTH,  320);
	cvSetCaptureProperty (cap, CV_CAP_PROP_FRAME_HEIGHT, 240);

	// 入力画像から特徴点を抽出
	IplImage* src_img_rgb = cvLoadImage (argv[1]);


	// 入力画像の特徴点を表示
	IplImage* src_img_gray = 0;
	if (src_img_gray == 0) {
		src_img_gray = cvCreateImage (cvGetSize(src_img_rgb), 8, 1);
	}
	cvCvtColor (src_img_rgb, src_img_gray, CV_RGB2GRAY);

	// ここからカメラからキャプチャした画像を処理するループ

	double threshold      = 1.0;
	double edge_threshold = 8.0;
	double magnification  = 3.0;

	// SIFTの特徴点検出・特徴量抽出器を用意
	cv::SiftFeatureDetector detector(threshold, edge_threshold );
	cv::SiftDescriptorExtractor extractor( magnification );

	// SURFの場合
	//cv::SurfFeatureDetector detector;
	//cv::SurfDescriptorExtractor extractor;

	// 画像1から特徴点を検出
	std::vector<cv::KeyPoint> keypoints1;
	cv::Mat mat1(src_img_gray);
	detector.detect( mat1, keypoints1 );
	// 画像1の特徴点における特徴量を抽出
	cv::Mat descriptor1;
	extractor.compute( mat1, keypoints1, descriptor1 );

	//表示用出力画像
	IplImage * stacked;


	while (true) {
		double st = (double)cvGetTickCount();
		// キャプチャデバイスから画像を取得
		cap_img_rgb = cvQueryFrame (cap);

		if (cap_img_gray == 0) {
			cap_img_gray = cvCreateImage (cvGetSize(cap_img_rgb), 8, 1);
		}
		cvCvtColor (cap_img_rgb, cap_img_gray, CV_RGB2GRAY);

		// 画像2から特徴点を検出
		cv::Mat mat(cap_img_gray);

		std::vector<cv::KeyPoint> keypoints2;
		detector.detect( mat, keypoints2 );


		// 画像2の特徴点における特徴量を抽出
		cv::Mat descriptor2;
		extractor.compute( mat, keypoints2, descriptor2 );

		// 対応点を求める
		vector< cv::DMatch > matches_o;
		vector< cv::DMatch > matches;

		// 特徴量比較による特徴点の対応付け
		cv::FlannBasedMatcher matcher;
		matcher.match(descriptor2, descriptor1, matches_o );
		// 類似度が高かった対応付けのみを抽出
		for(int i = 0;i < matches_o.size();i++)
		{
			if(sqrt(matches_o[i].distance/128.0) < 1.5)
			{
				matches.push_back(matches_o[i]);
			}
		}


		// 描画用画像の作成
		stacked = stack_imgs( src_img_rgb, cap_img_rgb);

		// 特徴点描画
		for(int i = 0;i < keypoints1.size();i++)
		{
			CvPoint center;
			center.x = keypoints1[i].pt.x;
			center.y = keypoints1[i].pt.y;
			cvCircle(stacked, center, 2, CV_RGB(160,0,0)); 
		};
		for(int i = 0;i < keypoints2.size();i++)
		{
			CvPoint center;
			center.x = keypoints2[i].pt.x;
			center.y = keypoints2[i].pt.y + src_img_rgb->height;
			cvCircle(stacked, center, 2, CV_RGB(160,0,0)); 
		};

		if(matches.size() > 4)
		{
			std::vector< cv::Vec2f > points1( matches.size());
			std::vector< cv::Vec2f > points2( matches.size());
			for(int i = 0;i < matches.size();i++)
			{
				CvPoint pt1, pt2;
				pt1.x = keypoints1[matches[i].trainIdx].pt.x;
				pt1.y = keypoints1[matches[i].trainIdx].pt.y;
				pt2.x = keypoints2[matches[i].queryIdx].pt.x;
				pt2.y = keypoints2[matches[i].queryIdx].pt.y + src_img_rgb->height;
				cvLine(stacked, pt1,pt2, CV_RGB(255,0,0));

				// 対応点ペアの作成
				pt1.x = keypoints1[matches[i].trainIdx].pt.x;
				pt1.y = keypoints1[matches[i].trainIdx].pt.y;
				pt2.x = keypoints2[matches[i].queryIdx].pt.x;
				pt2.y = keypoints2[matches[i].queryIdx].pt.y;
				points1[i][0] = pt1.x;
				points1[i][1] = pt1.y;
				points2[i][0] = pt2.x;
				points2[i][1] = pt2.y;
			};
			// RANSACによるホモグラフィ計算
			cv::Mat H;		
			H = cv::findHomography( points1, points2,  CV_RANSAC, 5.0);	

			// 結果を描画
			{
				CvPoint pt1, pt2;
				int B = 40;
				CvPoint xpt1, xpt2, xpt3, xpt4, pt;
				pt.x = 128-B;pt.y = 128 - B;
				xpt1 = persp_xform_pt( pt, H );
				pt.x = 128+B;pt.y = 128 - B;
				xpt2 = persp_xform_pt( pt, H );
				pt.x = 128+B;pt.y = 128 + B;
				xpt3 = persp_xform_pt( pt, H );
				pt.x = 128-B;pt.y = 128 + B;
				xpt4 = persp_xform_pt( pt, H );
				pt1.x = xpt1.x;pt1.y = xpt1.y + src_img_rgb->height;
				pt2.x = xpt2.x;pt2.y = xpt2.y + src_img_rgb->height;
				cvLine( stacked, pt1, pt2, CV_RGB(0, 255, 0), 2, 8, 0 );
				pt1.x = xpt2.x;pt1.y = xpt2.y + src_img_rgb->height;
				pt2.x = xpt3.x;pt2.y = xpt3.y + src_img_rgb->height;
				cvLine( stacked, pt1, pt2, CV_RGB(0, 255, 0), 2, 8, 0 );
				pt1.x = xpt3.x;pt1.y = xpt3.y + src_img_rgb->height;
				pt2.x = xpt4.x;pt2.y = xpt4.y + src_img_rgb->height;
				cvLine( stacked, pt1, pt2, CV_RGB(0, 255, 0), 2, 8, 0 );
				pt1.x = xpt4.x;pt1.y = xpt4.y + src_img_rgb->height;
				pt2.x = xpt1.x;pt2.y = xpt1.y + src_img_rgb->height;
				cvLine( stacked, pt1, pt2, CV_RGB(0, 255, 0), 2, 8, 0 );
			}
		};
		// 処理結果を表示
		cvShowImage("livecapture", stacked);

		// ESCキーを押したら終了
		int c = cvWaitKey(10);
		if (c == 27) break;
	}

	// 終了処理
	cvDestroyAllWindows ();
	cvReleaseImage (&src_img_gray);
	cvReleaseImage (&src_img_rgb);
	cvReleaseImage (&cap_img_gray);
	cvReleaseCapture (&cap);
	cvReleaseMemStorage (&storage);

	return (0);
}

参考サイト
[1]http://miyabiarts.wordpress.com/2011/01/21/opencv%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E7%89%B9%E5%BE%B4%E7%82%B9%E5%AF%BE%E5%BF%9C%E4%BB%98%E3%81%91/