« SHGetFolderLocation | トップページ | BCB6のテンプレートクラスのテンプレート引数 »

2005年2月24日 (木)

自動閾値判別分析二値化 - 大津の方法

Uint	Binarize::GetThresholdByOptimizedOtsu( const std::vector< Uint8 >& picture )
{
	//画像の先頭ポインタを取得
	const Uint8 * pPicture = &picture[0];

	//ヒストグラム用バッファを用意
	std::vector<double> histogram(256, 0);

	//ヒストグラムを作成
	TB_LOOP_1( picture.size() )
		++histogram[*pPicture++];

	//ヒストグラムの各要素を画像サイズで除算して正規化ヒストグラム(濃度の確率分布)を作成
	std::transform(histogram.begin(), histogram.end(), histogram.begin(), std::bind2nd(std::divides<double>(), picture.size()));

	//濃度分布の0次モーメント用のバッファを用意
	std::vector<double> partial0thMoment(256);

	//全体の部分和を計算({1,2,3,4}→{1,3,6,10})
	std::partial_sum(histogram.begin(), histogram.end(), partial0thMoment.begin());

	//濃度分布の1次モーメント用のバッファを用意
	std::vector<double> partial1stMoment(256);
	//正規化ヒストグラムに輝度をかけたものをバッファにコピー
	TB_LOOP_1( 256 )
		partial1stMoment[index] = index*histogram[index];
	//それの部分和を計算
	std::partial_sum(partial1stMoment.begin(), partial1stMoment.end(), partial1stMoment.begin());
	//全平均輝度レベル
	double total1stMoment = partial1stMoment.back();

	//クラス内分散
	std::vector<double> interClassVariance(256);
	TB_LOOP_1( 256 )
	{
		//クラス内分散を求める。(全平均輝度レベル×輝度i間での濃度分布の0次モーメント-輝度i間での濃度分布の1次モーメント)^2を
		double temp = total1stMoment * partial0thMoment[index] - partial1stMoment[index];
		//輝度i間での濃度分布の0次モーメント×(1-輝度i間での濃度分布の0次モーメント)で割る。
		interClassVariance[index] = temp*temp / (partial0thMoment[index]*(1-partial0thMoment[index]));
		//この辺は基本的なアルゴリズムを数学的にかなり畳み込んでる。
		//おそらく原本は"Feature Extraction & Image Processing" "Mark S. Nixon, Alberto Aguado" ISBN: 0750650788 の p77~。
		//訳だと"はじめての画像処理技術    ビギナーズブックス" "岡崎 彰夫" ISBN: 4769351224 の p78~。
	}
	//もともとはクラス間分散/クラス内分散でもっとも大きな値をとるような閾値が最適閾値なのだけど、
	//数学的にクラス間分散/クラス内分散が最大となる閾値とクラス内分散が最も大きくなる閾値が等価。よってクラス内分散の最大値となる閾値を求める。
	return std::max_element(interClassVariance.begin(), interClassVariance.end()) - interClassVariance.begin();
}

|

« SHGetFolderLocation | トップページ | BCB6のテンプレートクラスのテンプレート引数 »

コメント

この記事へのコメントは終了しました。