なんとなく、ふわっと・・

写真と画像処理関係とひとりごとをなんとなく書き溜めていきたい

色をかぞえる

2007-09-26 19:46:57 | C#(Graphics)
24ビットカラーの画像の中の色の数をかぞえるために、これまでに
ArrayList を使った関数をライブラリでつくってきた。ところで、
最近、申し訳ないがどこか探せないのだが Delphi で TBits クラスを
つかった実装を見かけた。論理的には、ArrayList で全色を保持して
ソートすることにより、色数をかぞえるよりスマートで、画像のサイズ
が大きくなるほど、速いと思われる。

C# で Delphi の TBits に相当するクラスは BitArray クラスである。
これは項目ごとに Boolean 値を保持できる。これをつかって、色を
かぞえるのは簡単かつソートがいらないので高速であるはずである。

さっそく試してみた。今回試した色をかぞえる画像はこれである。


ラ・フランドル、二ノ宮2、つくば市

結果は、以下に示すように、これまでの関数より2倍くらい速い。
ライブラリも変更することにしよう。






using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

using System.Collections;

namespace CountColors
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static int CountColors(Bitmap bmp)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return -1;

            int w = bmp.Width;
            int h = bmp.Height;

            BitArray ba = new BitArray(0x1000000, false);

            int count = 0;
            int indx;
            int ir;

            BmpProc24 src = new BmpProc24(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    ir = src.IndexR(x, y);
                    indx = (int)((((src[ir] << 8) | src[ir - 1]) << 8) | src[ir - 2]);
                    if (!ba[indx])
                    {
                        ba[indx] = true;
                        count++;
                    }
                }

            src.Dispose();

            return count;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\LaFlandre.png");

            StopWatch.Start();

            int cn = CountColors(bmp);

            StopWatch.Stop();            

            label1.Text = cn.ToString() + " colors";
            label2.Text = StopWatch.time.ToString() + " ms";


            StopWatch.Start();

            cn = ImgUtils.CountColors(bmp);

            StopWatch.Stop();

            label3.Text = cn.ToString() + " colors";
            label4.Text = StopWatch.time.ToString() + " ms";


            bmp.Dispose();

        }
    }
}

Comments (2)    この記事についてブログを書く
« ちくちく | TOP | りんご »

2 Comments

コメント日が  古い順  |   新しい順
今日はこの技術が役に立ちました (myugaru)
2008-01-29 15:53:30
古い日記にコメントですみません(笑
今日、仕事で画面で押されたキーによって画面が変わるというのを実装するときに、キー定義をカスタマイズできるようにしなくてはならなくなりました。
そのときにキーの押された情報保存にbitarrayが使えるように思い出しました。
それというのもjunkiさんのこの記事をずいぶん前に参考にして勉強させてもらっていたおかげです。本当に助かりました。
junkiさんが日ごろおっしゃっているように、私も会社という出先でこちらのページを簡単に確認できましたし、やはりネット上に情報保存しておくというのはIT技術の一番素晴らしい利用方法だとつくづく実感しました。
返信する
ネット上に情報保存 (junki)
2008-01-30 01:20:11

myugaru さん、こんばんは。

森の中で、木の数を数えるとき、同じ木を二度数えないように、しるしをつけると良い、と小学校の時に教わりました。プログラムで、同じことをするとき、しるしとして最も容量が小さいのが Boolean ですよね。なにしろ1ビットしか使いませんから。この色の数を数える場合でも、どこかで Delphi のコードを見て、なるほど、と感嘆したことを覚えています。

>ネット上に情報保存しておくというのはIT技術の一番素晴らしい利用方法だとつくづく実感しました。

そうですね。わたしもそのことを強く感じています。プログラムコードをネット上に公開するのは、かなり勇気がいることですが、非常に便利ですよね。他人のための情報提供という側面もありますが、実は、自分が一番便利に使っているのかも知れません。わたしは、livedoor と lolipop のブログに大量のコードを公開していますが、自分のPCのハードディスクに眠らせておくより、はるかに便利にアクセスできます。思いつきやテストのためのコードは、フローであるブログに気軽に書き込んでメモとします。ある程度まとまってきたら、スタティックであるホームページにまとめておきます。プログラムコードに限らず、アイデアのメモや備忘録のためにブログを利用するのは、ものすごく有効なようです。

コメント、ありがとうございます。

返信する

post a comment