« 2005年1月 | トップページ | 2005年3月 »

2005年2月24日 (木)

BCB6のテンプレートクラスのテンプレート引数

BCB6のテンプレートクラスのメンバ関数をクラス外で宣言するとき、テンプレート引数の引数名自体が同一でないとコンパイルエラーになる。

| | コメント (0)

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

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();
}

| | コメント (0)

2005年2月18日 (金)

SHGetFolderLocation

VC6SP5+PSDKの環境でもスタティックリンクできない。ダイナミックリンクすればとりあえずコンパイルは通る。

| | コメント (0) | トラックバック (0)

2005年2月 9日 (水)

重なり合うコントロールのInvalidRect

子コントロール同士で重なりあっていて、それぞれWM_PAINTで描画処理している場合、下のコントロールがWM_PAINTを処理してしまって上のコントロールにWM_PAINTが行かないときがある。
BeginPaint中はValidateRectは使えないので、下のコントロールのWM_PAINTの処理が終わり次第上のコントロールにInvalidateRectしてやればよい。

| | コメント (0) | トラックバック (0)

2005年2月 3日 (木)

JNetHack::倉庫番::4F

続きを読む "JNetHack::倉庫番::4F"

| | コメント (0)

JNetHack::倉庫番::3F

続きを読む "JNetHack::倉庫番::3F"

| | コメント (0) | トラックバック (0)

JNetHack::倉庫番::2F

続きを読む "JNetHack::倉庫番::2F"

| | コメント (0) | トラックバック (0)

2005年2月 1日 (火)

他プロセスのコンソールアプリケーションを全画面表示にする

あんまり自信が無いんだけど、この手の資料の日本語のものが無いので参考までに。


void	Process::SetFullScreenMode()
{
	//プロセス起動直後にAttachConsoleしようとするとたいていうまく行かない。
	Sleep(1000);
	if( AttachConsole( TB_ENFORCE( API(), GetProcessId( mProcess ) ) ) )
	{
		TB_ENFORCE_TO_THROW
		{
			DllProc< BOOL (WINAPI*) (HANDLE,DWORD,COORD*) >	SetConsoleDisplayMode( FilePath( FolderPath::GetWindowsFolder(), "kernel32.dll" ), "SetConsoleDisplayMode" );
			COORD	coord;
			const int CONSOLE_FULLSCREEN_MODE = 1;
			TB_ENFORCE( API(), SetConsoleDisplayMode()( TB_ENFORCE( API(INVALID_HANDLE_VALUE), GetStdHandle( STD_OUTPUT_HANDLE ) ), CONSOLE_FULLSCREEN_MODE, &coord ) );
		}
		TB_ENFORCE_CATCH
		{
			//まずコンソールウインドウのハンドルを何とかしてとってくる。
			//そのためにウインドウタイトルをユニークなIDで置き換える。
			//同じアルゴリズムを使うプログラムと競合する可能性が(0%に近いけど)あるのでIdはGUIDを使う。
			std::string	guid = "{6A47F119-E665-4533-99CB-BDF3ABE2B1D0}";
			//タイトルをバックアップ
			StringReceiver	title;
			TB_ENFORCE( API(), GetConsoleTitle(title.Lock( 1024 ), 1023 ) );
			//置き換える。
			TB_ENFORCE( API(), SetConsoleTitle(guid.c_str()) );
			//別プロセスなのでウインドウタイトルをセットするためのコンテキストスイッチを起こして待つ。
			Sleep(50);
			//ウインドウタイトルを検索してハンドルを得る。
			//win9x系のコンソールのウインドウクラスはtty
			HWND	hConWnd = TB_ENFORCE( API<HWND>(NULL), FindWindow("tty", guid.c_str()) );
			//タイトルを元に戻す
			TB_ENFORCE( API(), SetConsoleTitle(title.UnLock().c_str()) );

			// pause before changing to fullscreen
			//Sleep(450);

			//コンソールウインドウにWM_COMMAND,57359,0を送ると全画面化する。
			SendMessage( hConWnd, WM_COMMAND, 57359, 0 );
		}
		TB_ENFORCE( API(), FreeConsole() );
	}
}

XPのSP2ならAttachConsole→SetConsoleDisplayModeで一発。
ただしSetConsoleDisplayModeはMSDN::English::Win32API::SetConsoleDisplayModeに"Header Declared in Wincon.h; include Windows.h."って書いてあるのに最新版のプラットフォームSDKのWincon.hにも無いのでKernel32.dllから気合でLoadLibrary&GetProcAddressしないとだめです。

挙句にAttachConsoleがなぜかかなりの確率で失敗します。
エラーメッセージは「ハンドルが無効です。」…いや引数ハンドルじゃないし。ハンドルはハンドルで有効だし。もちろんプロセスIDだってあってるよ!
ていうかGetLastError設定してないんじゃなかろか。


while( !AttachConsole( mProcessID ) )
	Sleep(500);
みたいなコードを書いても一度失敗したらなぜか二度と成功しません(アタッチしたい相手先のコンソールは元気に動いてます)。
というわけでAttachConsoleで失敗したら泣く泣く素直にあきらめてます。

また、Win9x系ではコンソールウインドウにWM_COMMANDのWPARAMが57359を送ると全画面化するそうです。
(Ref: http://mureakuha.com/koodikirjasto/635)

ただしこの技はNTでは使えません。
WPARAMが違うのかと思ってSPYでWM_COMMANDメッセージをみようと思ったらSPYがサブクラス化に失敗するので全ウインドウのWM_COMMANDを見張ったところ、確かにモードが変わったとき異なるWPARAMが送られてたのでそいつを上のコードの57359の変わりに送ってみたところ…変化なし。
SetConsoleDisplayModeはなんか"Requires Windows XP."だそうで、結局2000とかのコンソールを最大化させる手段はAlt+Enterをコンソールウインドウに送りつけるとかしかないかも。

| | コメント (0)

NetHack 3.4.3 における祭壇の利用法

寺院を乗っ取る方法

上記の通りノームの鉱山あたりの寺院を乗っ取ると序盤でかなりおいしい思いができます。
が、3.4.3になってパッチがあたったのか上記のページのやり方では乗っ取れません。
「手順」の


   ------ ------ ------ ------ ------ ------ ------ ------
   |....| |....| |....| |....| |....| |....| |....| |....|
   |....| |^...| |^...| |^...| |^O..| |^O..| |^O..| |^@..|
   |.._.| |.^O.| |P^O.| |P^O.| |P^@.| |P^_.| |P^_.| |O^_.|
   |....| |.P@.| |..@.| |...@| |....| |.@..| |.^@.| |P^..|
   -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.----
で、僧侶が梃子でも動こうとしなくなるのです。というかプレイヤーが寺院に入るとほとんど祭壇の周り1マスから離れようとしなくなります。

もう乗っ取れないのかな?と思いがちですが、まだまだ抜け穴があります。
必要なものは祝福された大地の巻物とつるはしです。(あと固い兜があるとダメージを受けなくてすみます。)

まず運命の大迷宮の神託所レベルの更に1階下のレベルにある2つの上り階段の片方から入れる倉庫番レベルに行きます。
倉庫番の1階には大地の巻物が落ちているのでそれを拾ってきます。
そして1枚を祝福します。…何気にこれが大変ですが。運命の大迷宮を駆けずり回って自分の属性の祭壇を探してください。

祝福された大地の巻物が用意できたら寺院へ行って祭壇の上に立ちます。そして兜をかぶって巻物を読みます。
すると自分の上を含めて9マスに岩が落ちてきます。


------	------
|...@|	|....|
|P...|	|.```|
|.._.|	|.P@`|
|....|	|.```|
-.----	-.----
@:プレイヤー
P:僧侶
_:祭壇
このとき僧侶は自分の隣のますにいます。表示されていませんがこの僧侶の上にも岩があります。
岩を落としたら僧侶の隣の岩をつるはしで砕いて脱出します。


------	------	------
|....|	|....|	|.@..|
|.*``|	|.@``|	|.*``|
|.P@`|	|.P``|	|.P``|
|.```|	|.```|	|.```|
-.----	-.----	-.----
んでしばらく足踏みをすると僧侶が動きます。祭壇の周り1マスのうち動けるのはさっき砕いたマスだけなのでそこに移動するでしょう。


------
|.@..|
|.P``|
|.```|
|.```|
-.----
一見このまま僧侶はどこにも行かず固まるのかと思いきや、しばらく足踏みしてると別のマスに移動を始めます。


------
|.@..|
|.*``|
|P```|
|.```|
-.----
こうなったらしめたもの、砕いた岩のますのところに落とし穴を掘って祭壇のまわり一マスに僧侶をいけなくします。
後は僧侶を寺院から追い出したい方向に落とし穴や岩で閉じ込めます。
また、僧侶がこれない方向の岩を砕いて祭壇までの通り道を作ります。


------	------	------	 ------  ------  ------  ------  -.----  -@----  -.----  -.----
|....|	|....|	|....|	 |.P..|  |.P`.|  |P`@.|  |`@..|  |`@..|  |`...|  |....|  |....|
|.@``|	|@^``|	|.^``|	 |.^``|  |.^`@|  |.^`.|  |P^`.|  |P^`.|  |P^`.|  |@^`.|  |.^`@|
|P```|	|P```|	|.```.	 |.```@  |.```.  |.```.  |.```.  |.```.  |.```.  |````.  |``*`.
|.```|	|.```|	|P```|@  |.```|  |.```|  |.```|  |.```|  |.```|  |.```|  |P```|  |P```|
-.----	-.----	-.----	 -.----  -.----  -.----  -.----  -.----  -.----  -.----  -.----
と、まぁこんな感じで乗っ取り完了です。後は祭壇に死体をささげて転換して、レベル低ければ幽霊レベルアップ、その後は僧侶に蟻を召還してもらってレベル上げ&アーティファクトゲット!詳しくは前述のページを参照のこと。

| | コメント (0)

« 2005年1月 | トップページ | 2005年3月 »