- PR -

[C#] KnownColorの対応パレット(Bitmapクラス)を知りたい

投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2006-09-22 09:46
BitmapオブジェクトのPaletteのどこに任意のKnownColorがあるかを知る簡便な方法はありますか?

Palette.Entries[]を順番に照合して、KnownColorとパレット番号の対応を得ています。
この方法でも問題ありませんが、よりエレガントな解決方法はありますか?
Bitmapクラスに見落としている便利なメソッド(プロパティ)があるかも知れないと思い
質問します。

---------------------------

// 256諧調(PixelFormat.Format8bppIndexed)のBitmap専用メソッド

// KnownColorのColorPalette番号を得る
// 失敗したら-1を返す
int GetPaletteEntriesIndex(KnownColor k,Bitmap bmp)
{
Color c = Color.FromKnownColor(k);
int argb = c.ToArgb();
ColorPalette p = bmp.Palette;
int ans = -1;
for(int i = 0;i < 256;i++)
{
if(argb == p.Entries[i].ToArgb())
{
ans = i;
}
}
// 適合するパレット番号がなければ-1を返す
return ans;
}
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-09-26 21:46
エレガントな方法より、自分が理解できる方法の方が良いと思うのですが。。。

2点ほど。
なぜ、for 文でループする範囲が 256 固定なのでしょう?これが 256 に固定されているというのは、誰が保証するのでしょう?

何度もこのルーチンが呼ばれるなら、色情報をハッシュテーブル化しておけば、何度も比較することはない。違いますか?
_________________
Ahf
大ベテラン
会議室デビュー日: 2006/08/16
投稿数: 172
投稿日時: 2006-09-26 22:49
8bitビットマップ限定であれば、ひろしさんのロジックがスマートな気がします。

そういえば256色ってパレット面倒だったなぁ・・・とちょっと懐かしい気分です。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2006-09-27 12:58
ご回答ありがとうございます。

256諧調固定である理由
は単に処理の簡便化と速度アップのためです。
256諧調の場合BitmapDataが1画素1byteなのでアニメーション表示等応用性が要求
される場合書き換え処理が楽になるからです。

数色あるいは最大でも数十色程度の色の組み合わせ(SystemColorやKnownColor等)
で画面(PictureBox)に簡単な図面やチャートを描きたい場合が時々あります。
特殊事情としては静止画では無く動画の図形やチャートを描きたい時もあります。

呼び出し側のソースではRed,Green,Pink等良く知られた色名称で記述しておいて、
Bitmapインスタンスが生成した時に変換テーブルを作成します。
その時の処理ロジックを今回質問しました。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2006-09-27 13:07
引用:

ひろしさんの書き込み (2006-09-27 12:58) より:
単に処理の簡便化と速度アップのためです。


効果はほとんどない。
ぽぴ王子
ぬし
会議室デビュー日: 2006/03/24
投稿数: 475
お住まい・勤務地: お住まい:城・勤務地:城
投稿日時: 2006-09-27 14:18
こんにちは。

引用:

ひろしさんの書き込み (2006-09-27 12:58) より:

256諧調固定である理由
は単に処理の簡便化と速度アップのためです。
256諧調の場合BitmapDataが1画素1byteなのでアニメーション表示等応用性が要求
される場合書き換え処理が楽になるからです。


これだと、Jitta さんの質問の回答にはなりえないですよね。

  1. なぜ 256 固定なのか
  2. 256 固定で良いと誰が保証するのか

を質問されているので

  1. 256 階調(諧調は誤りですね)のビットマップを使用しているため
  2. ビットマップがの階調が 256 固定なので

といった感じが答えになると思います。

ただ、それでも私であれば後々のメンテナンス性を考えて
 for(int i = 0; i < p.Entries.Length; i++)
のように書くと思いますし、むしろ foreach で回すほうがエレガントと言えばエレ
ガント…かなあ?とか。
また
 // 適合するパレット番号がなければ-1を返す
 return ans;
のコメントは
 // 適合するパレット番号がなければ-1を返す
 int ans = -1;
の場所の方がいいのじゃないかとか、まぁ処理とまったく関係ないところも気にな
ります(個人的嗜好なのであまり気にしなくても良いかもしれません)。

むしろ「速度アップ」ということであれば

引用:

Jittaさんの書き込み (2006-09-26 21:46) より:

何度もこのルーチンが呼ばれるなら、色情報をハッシュテーブル化しておけば、何度も比較することはない。違いますか?


を一番初めに検討すべきかも…とは思いますが。

あと、ものすごく強引な手法(素人にはオススメできない)として、こんなのもあるかもしれません。

コード:

    Color c = Color.FromKnownColor(k);       // KnownColorからColorを取得
    Color c2 = Color.FromArgb(c.ToArgb());   // ARGB成分から改めてColorを作成
    return Array.IndexOf(bmp.Palette.Entries, c2);


でも私ならこんなの業務のコードには実装しませんけど(じゃあ書くなよ)。

_________________
ぽぴ王子@わんくま同盟
ぽぴ王子の人生プログラミング中 / ぽぴンち。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2006-09-27 20:16
回答ありがとうございます。

高速処理が必要なのでLockBits/UnlockBitsを前提に話をしていました。
GetPixel/SetPixelは非常に遅いので、いつもBitmapDataを直接加工しています。
その場合1画素1byteだと2,3,4byteの場合より、書き込むデータ量が1/2〜1/4になり、
またポインタのアドレス計算のための乗算の回数が削減できます。
そのような時には確かに効果があります。
説明足らずで混乱させてすみませんでした。

本題から離れますが、forループの評価部分でプロパティ使用は
パフォーマンス低下が発生することがあるので注意が必要です。

以前、
for(int i = 0; i < bmp.Size; i++)
のような記述をして痛い目にあったことがあります。(処理が遅くて)
int size = bmp.Size;
for(int i = 0; i < size; i++)

Paletteの場合はループが高々256回なので問題ないと思いますが、

それから、
(使うかどうか別としても)このコード面白いですね。私は発想できませんでした。
// Color c = Color.FromKnownColor(k); // KnownColorからColorを取得
// Color c2 = Color.FromArgb(c.ToArgb()); // ARGB成分から改めてColorを作成
// return Array.IndexOf(bmp.Palette.Entries, c2);
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-09-27 21:43
ぽぴ王子さんに言われてしまった。。。

例えば、「同じプログラム中で作っているビットマップしか使わないから」であれば、回答といえます。
で、たぶん、そういうことなのでしょう。
コード:
Hashtable CreatePalleteMap(Bitmap bmp) {
	Hashtable PaletteMap = new Hashtable();
	ColorPalette palette = bmp.Palette;
	for (int index = 0; index < palette.Entries.Length; index++) {
		String colorName = string.Empty;
		KnownColor colorNameIndex = palette.Entries[index].ToKnownColor();
		if (colorNameIndex == 0) {
			colorName = palette.Entries[index].ToString();
		} else {
			colorName = colorNameIndex.ToString();
		}
		if (PaletteMap.Contains(colorName) == false) {
			PaletteMap.Add(colorName, index);
		}
	}
	return PaletteMap;
}


msdn 見たところ、未定義の KnownColor が判別できませんでした。if 文は、C# では enum と整数を比較できない、とかっていう警告が出るはずなので、適切に直すように。


引用:

本題から離れますが、forループの評価部分でプロパティ使用は
パフォーマンス低下が発生することがあるので注意が必要です。


痛い目を見たコードは、提示できますか?
C# であれば、そのようなことは発生しないと思います。
VB6.0 以前であれば、毎回参照をたどるので、ループ回数が多いほど遅くなると思います。

_________________

スキルアップ/キャリアアップ(JOB@IT)