7

私はいたるところを見てきましたが、画像が空白かどうかを確認する方法の標準(私が見ることができた)はないようです。C# の場合

私にはこれを行う方法がありますが、画像が空白かどうかを確認する正しい方法を知りたいので、将来誰もが知ることができます.

たくさんのコードをコピーして貼り付けるつもりはありません。必要に応じて喜んで行いますが、最初に、画像が空白かどうかを確認する方法を説明したいと思います。

.jpg 画像を取得し、その幅を取得します。たとえば、500 ピクセルを 2 で割ると 250 になります。

次に、(幅250、高さi)の位置にあるすべてのピクセルの色を確認します(画像の高さを繰り返します。

これが行うことは、画像のピクセルの中央の行のみを垂直方向にチェックすることです。すべてのピクセルをチェックして、色が白以外であるかどうかを確認します。私はこれを行ったので、すべての 500*高さのピクセルを検索する必要はありません。ほとんどの場合、ページの中央で色に出くわすからです。

その作業...少し遅い...これを行うためのより良い方法が必要ですか? 垂直方向に 2/3/4 行を検索するように変更して、空白ではないページを見つける可能性を高めることができますが、それにはさらに時間がかかります.

(また、この場合、画像のサイズを使用して何かが含まれているかどうかを確認することはできません。これは、2 つの文が含まれるページと空白のページのサイズが互いに近すぎるためです)

ソリューションが追加された後。

ソリューションの実装と理解に役立つリソース。

(最初の Web サイトでは、記載されている Pizelformat は実際には Pixelformat であることに注意してください) - 私が知っている小さなエラーは、言及しただけで、混乱を招く可能性があります。

ピクセルハンティングを高速化する方法を実装した後、速度はそれほど向上しませんでした。だから私は何か間違ったことをしていると思うでしょう。

古い時間 = 15.63 画像 40 枚。

新しい時間 = 15.43 画像 40 個の場合

コードが一連のピクセルに「ロック」されていることを引用したDocMaxの素晴らしい記事で見ました。(またはそれが私がそれを理解した方法です)それで、私がしたことは、各ページのピクセルの中央の行にロックすることです. それは正しい行動でしょうか?

private int testPixels(String sourceDir)
    {
         //iterate through images
        string[] fileEntries = Directory.GetFiles(sourceDir).Where(x => x.Contains("JPG")).ToArray();

        var q = from string x in Directory.GetFiles(sourceDir)
                where x.ToLower().EndsWith(".jpg")
                select new FileInfo(x);

        int holder = 1;
        foreach (var z in q)
        {
            Bitmap mybm= Bitmap.FromFile(z.FullName) as Bitmap;
            int blank = getPixelData2(mybm);
           
            if (blank == 0)
            {
                holder = 0;
                break;
            }
        }
        return holder;
    }

そして、クラス

private unsafe int getPixelData2(Bitmap bm)
        {
            BitmapData bmd = bm.LockBits(new System.Drawing.Rectangle((bm.Width / 2), 0, 1, bm.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);

            int blue;
            int green;
            int red;

            int width = bmd.Width / 2;
            for (int y = 0; y < bmd.Height; y++)
            {
                byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);

                blue = row[width * 3];
                green = row[width * 2];
                red = row[width * 1];

                // Console.WriteLine("Blue= " + blue + " Green= " + green + " Red= " + red);
                //Check to see if there is some form of color
                if ((blue != 255) || (green != 255) || (red != 255))
                {
                    bm.Dispose();
                    return 1;
                }
            }
            bm.Dispose();
            return 0;
        }
4

3 に答える 3

9

間違える可能性を許容できるのであれば、このアプローチは問題ないように思えます。私の場合、エラーに対処するために常に視覚的な確認がありましたが、非常に似たようなことをしました。

パフォーマンスに関して、重要な未解決の問題は、テストするピクセルをどのように取得するかです。を使用している場合Bitmap.GetPixel、パフォーマンスの問題が必ず発生します。(Google で「Bitmap.GetPixel slow」を検索して、多くの議論を参照してください。)

一度にすべてのピクセルを取得してからループすることで、はるかに優れたパフォーマンスが得られます。個人的には、Bob Powell の LockBits の議論が明確で完全であることを気に入っています。このアプローチでは、パフォーマンスのニーズによっては、すべてのピクセルをチェックすることが適切な場合があります。

于 2012-10-02T05:34:41.697 に答える
2

System.Drawing.Bitmap を使用している場合は、次の方法で (大幅に) 高速化できます。

  1. GetPixel を使用してピクセルにアクセスするのではなく、LockBits と UnlockBits を使用してイメージ ビットマップを通常のメモリにコピーします。使用方法については、 MSDN ドキュメントの例を参照してください。
  2. for ループで Width、Height、または Size プロパティを呼び出していません。Size を 1 回呼び出し、値をローカル変数に格納し、それらをループで使用します。

ノート:

  1. System.Drawing.Bitmap を使用する場合、イメージがデバイス メモリにある可能性があり、アクセスに時間がかかる場合があります。
  2. 画像をビットマップにロードすると、他の形式の方が扱いにくいため、既に RGB 形式に変換されているかどうかは覚えていませんが、そうでない場合は、元の画像と同じサイズの RGB ビットマップを作成できます。 Graphic オブジェクト (Graphics.FromImage) を取得し、DrawImage を使用して RGB ビットマップで元の画像を描画します。

編集:DocMaxによるパンチに打ち勝ちます。

いずれにせよ、速度のために、C# ラッパーを含む優れたFreeImageなどの代替ライブラリを使用することもできます。

于 2012-10-02T05:49:02.017 に答える
0

画像を 1x1 にスケーリングし、1 ピクセルを確認します

new Bitmap(previousImage, new Size(1, 1));

于 2014-12-04T15:03:50.840 に答える