OpenCVでcv::Algorithmのパラメータを表示する

OpenCVのcv::Algorithmのパラメータの名前・型・値を表示する.

cv::Algorithm

OpenCV2.4から導入された基底クラスcv::Algorithm.以下の引用のように,色々と便利.

新しい基底クラス cv::Algorithm の導入.これは「些細なものではない」全てのOpenCVの機能の基底クラスになる予定。この基底クラスの特徴は以下のとおり。

  1. 「仮想コンストラクタ」すなわち各アルゴリズムのインスタンスをアルゴリズム名から作成可能。
  2. 利用可能なアルゴリズムのリストを所有。
  3. アルゴリズム名によりそのアルゴリズムのパラメータの取得と設定が可能.
  4. アルゴリズムのパラメータを XML/YAML ファイルに保存し、それをあとでロードする事が可能。
【ニュース】OpenCV2.4がリリース | DERiVE コンピュータビジョン ブログ & メルマガ

ぱっと見ただけでも,
FeatureDetectorDescriptorExtractorDescriptorMatcherFaceRecognizerCLAHEEMBackgroundSubtractorDenseOpticalFlow
あたりのアルゴリズムがAlgorithmクラスの派生クラスになっている.恐らくもっとありそうだし,今後も増える模様.

インターフェース

Algorithm::setで指定した名前のパラメータをセットしたり,Algorithm::getで指定した名前のパラメータをセットしたりできる.その際,OpenCVのリファレンスを当たるか,Algorithm::getParamsとAlgorithm::paramTypeでパラメータ名と型を調べるとかしないといけない.そして,Algorithm::getするときは,テンプレートで型指定したりしなくちゃいけなくてやや面倒.

なので,アルゴリズムのパラメータ名と型,値の一覧を表示する関数printParamsを作った.

/**
 * Algorithmのパラメータ一覧を表示する
 * @param algo パラメータを表示したいアルゴリズム
 */
void printParams(const Algorithm* algo);

中身は長いので先に使用例を示す.

使用例

printParams以下のコードのように使用できる.生成したアルゴリズムのオブジェクトを引数として渡すだけである.

Ptr<FeatureDetector> fd = FeatureDetector::create("STAR");
printParams(fd);
Ptr<EM> em = new EM();
printParams(em);

結果は以下のように表示される.型,パラメータ名,値が一覧されている.

Parameters of Feature2D.STAR
 - integer lineThresholdBinarized = 8
 - integer lineThresholdProjected = 10
 - integer maxSize = 45
 - integer responseThreshold = 30
 - integer suppressNonmaxSize = 5

Parameters of StatModel.EM
 - integer covMatType = 1
 - std::vector<cv::Mat> covs =
 - double epsilon = 1.19209e-007
 - integer maxIters = 100
 - cv::Mat means = []
 - integer nclusters = 5
 - cv::Mat weights = []

パラメータを変更したい場合は,Algorithm::setメソッドで以下のように変更できる.

fd->set("maxSize", 32);

ソースコード

以下,printParamsのソースコード.パラメータの型ごとに処理が分かれているためコードは長いが,大したことはしていない.ほぼOpenCVのソースコードから引っ張ってきただけ.

using namespace cv;

string getNameOfType(int argType)
{
	switch(argType)
	{
		case Param::INT: return "integer";
		case Param::SHORT: return "short";
		case Param::BOOLEAN: return "boolean";
		case Param::REAL: return "double";
		case Param::STRING: return "string";
		case Param::MAT: return "cv::Mat";
		case Param::MAT_VECTOR: return "std::vector<cv::Mat>";
		case Param::ALGORITHM: return "algorithm";
		case Param::FLOAT: return "float";
		case Param::UNSIGNED_INT: return "unsigned int";
		case Param::UINT64: return "unsigned int64";
		case Param::UCHAR: return "unsigned char";
		default: CV_Error(CV_StsBadArg, "Wrong argument type");
	}
	return "";
}

void printParams(const Algorithm* algo)
{
	std::cout << "Parameters of " << algo->name() << std::endl;
	std::vector<std::string> names;
	algo->getParams(names);
	for (int i = 0; i < names.size(); ++ i)
	{
		int type = algo->paramType(names[i]);
		std::cout << " - " << getNameOfType(type) << " " << names[i] << " = ";
		if( type == Param::INT )
			std::cout << algo->get<int>(names[i]) << std::endl;
		else if( type == Param::BOOLEAN )
			std::cout << algo->get<bool>(names[i]) << std::endl;
		else if( type == Param::SHORT )
			std::cout << (int)algo->get<short>(names[i]) << std::endl;
		else if( type == Param::REAL )
			std::cout << algo->get<double>(names[i]) << std::endl;
		else if( type == Param::STRING )
			std::cout << algo->get<string>(names[i]) << std::endl;
		else if( type == Param::MAT )
			std::cout << algo->get<Mat>(names[i]) << std::endl;
		else if( type == Param::MAT_VECTOR )
		{
			std::vector<Mat> mats = algo->get<vector<Mat>>(names[i]);
			for (int j = 0; j < mats.size(); ++ j)
				std::cout << mats[j] << std::endl;
			std::cout << std::endl;
		}
		else if( type == Param::ALGORITHM )
		{
			Ptr<Algorithm> nestedAlgo = algo->get<Algorithm>(names[i]);
			std::cout << nestedAlgo->name() << std::endl;
		}
		else if( type == Param::FLOAT)
			std::cout << (float)algo->getDouble(names[i]) << std::endl;
		else if( type == Param::UNSIGNED_INT)
			std::cout << (unsigned int)algo->getInt(names[i]) << std::endl;
		else if( type == Param::UINT64)
			std::cout << (unsigned long long)algo->getInt(names[i]) << std::endl;
		else if( type == Param::UCHAR)
			std::cout << (unsigned char)algo->getInt(names[i]) << std::endl;
		else
		{
			string msg = format("unknown/unsupported type of '%s' parameter == %d", names[i].c_str(), type);
			CV_Error( CV_StsUnsupportedFormat, msg.c_str());
		}
	}
}