ビットマップの色数計算
フルカラー24ビット形式ビットマップ(DIB)内の色を数えてみます。これは、ビットマップ内に何色の色があるかを調べる処理で、手順としてはビットマップ内にある色の数値(RGB各8ビット)のリストを作成して行く処理になるでしょう。
画像の色リストを作成する
ビットマップ内の色をリストアップするには、まず各ピクセルを順番に調べ、新しく出てきた色をリストアップして行きます。つまり、「画像内に存在する色(ピクセルの値)」を保存するリストを作成する必要があるわけです。
ビットマップの各ピクセルは24ビットですが、今回は処理の効率化のために32ビットで扱う事にしてリストの方も32ビット(DWORD型)配列として定義しました。
24ビットの各ピクセルの値を32ビットに変換するには、32ビット変数にピクセルの値である3バイト分をコピーすれば良いでしょう。例えば、先頭アドレスlpBMP、横幅がdwLengthのビットマップバッファの(x, y)の色を32ビット変数dwPixelに格納するには以下のようにします。
/* (x,y)の色をdwPixelに32ビットで格納 */
CopyMemory(&dwPixel,lpBMP+x*3+y*dwLength,3);
次は、過去の色リストの作成です。リストの作成は、これまで調べてきたピクセルの色と比較して行き、一度も現れた事のない色ならリストに追加します。まず、リストの総数を変数dwColorsでカウントし、dwColors回リストの配列を参照するループを作りましょう。
後は、このループでリストの色と今調べているピクセルの色を比べて行くだけです。このループは、リストの色とピクセルの色が一致したら中断するようにすると、ループが最後まで(dwColors回)実行されたかを調べる事でリストにピクセルの色があったどうかも調べられる事になります。
for (i=0;i<dwHeight;i++)
for (j=0;j<dwWidth;j++) {
dwPixel=0;
/* (j,i)の色をdwPixelに32ビットで格納 */
CopyMemory(&dwPixel,lpBMP+j*3+i*dwLength,3);
/* 過去の色リストと比較 */
for (k=0;k<dwCount;k++)
if (dwPixel==dwColors[k]) /* これまでに出てきた色なら中止 */
break;
/* 新しい色なら過去の色リストに追加 */
if (k==dwCount)
dwColors[dwCount++]=dwPixel;
}
ただし、リストが大きくなると処理に膨大な時間がかかるようになるので、リスト内の色が一定の数を越えたら途中で処理を中断するようにするか、別スレッドで処理した方が良いかもしれません。
DWORD count(void) { /* ビットマップ内のに対する色数を数える */
DWORD i,j,k,dwCount=0,dwPixel,dwColors[4096];
for (i=0;i<dwHeight;i++)
for (j=0;j<dwWidth;j++) {
dwPixel=0;
/* (j,i)の色をdwPixelに32ビットで格納 */
CopyMemory(&dwPixel,lpBMP+j*3+i*dwLength,3);
/* 過去の色リストと比較 */
for (k=0;k<dwCount;k++)
if (dwPixel==dwColors[k])
break;
/* 新しい色なら過去の色リストに追加 */
if (k==dwCount)
dwColors[dwCount++]=dwPixel;
if (dwCount>=4096) /* 4096色以上なら中断 */
return 4096;
}
return dwCount;
}
プログラム
24ビットフルカラービットマップをウインドウにドラッグ&ドロップするか「読み込み」ボタンで読み込むと、そのビットマップ内の色数を数えてウインドウのタイトルバーに表示します。ただし、4096色以上あった時は「4096色」になります。