-1

指定された色で最初に見つかったピクセルのポイント/座標(x、y)を見つける必要があります。GetPixel()メソッドを使用しましたが、少し遅すぎてLockBitsを調べていました。しかし、これが実際に私の問題を解決できるかどうかはわかりません。LockBitsを使用して、見つかったピクセルのポイントを返すことはできますか?

これが私の現在のコードです:

public Point FindPixel(Image Screen, Color ColorToFind)
{
    Bitmap bit = new Bitmap(Screen);
    BitmapData bmpData = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height),
                                    ImageLockMode.ReadWrite,
                                    PixelFormat.Format32bppPArgb);
    unsafe
    {
        byte* ptrSrc = (byte*)bmpData.Scan0;
        for (int y = 0; y < bmpData.Height; y++)
        {
            for (int x = 0; x < bmpData.Width; x++)
            {
                Color c = bit.GetPixel(x, y);
                if (c == ColorToFind)
                    return new Point(x, y);
            }
        }
    }
    bit.UnlockBits(bmpData);
    return new Point(0, 0);
}
4

2 に答える 2

2

GetPixel()の使用をやめなかったので、先に進んでいません。代わりに次のように記述してください。

    int IntToFind = ColorToFind.ToArgb();
    int height = bmpData.Height;    // These properties are slow so read them only once
    int width = bmpData.Width;
    unsafe
    {
        for (int y = 0; y < height; y++)
        {
            int* pline = (int*)bmpData.Scan0 + y * bmpData.Stride/4;
            for (int x = 0; x < width; x++)
            {
                if (pline[x] == IntToFind)
                    return new Point(x, bit.Height - y - 1);
            }
        }
    }

行はビットマップに上下逆に格納されるため、奇妙な外観のPointコンストラクターが必要です。また、失敗時に新しいPoint(0、0)を返さないでください。これは、有効なピクセルです。

于 2012-02-12T17:34:20.637 に答える
1

コードに問題があることがいくつかあります。

  1. PixelFormat.Format32bppPArgbを使用しています-画像のピクセル形式を使用する必要があります。一致しない場合は、とにかくすべてのピクセルが内部でコピーされます。
  2. あなたはまだを使用してGetPixelいるので、この面倒なことはあなたに何の利点も与えません。

効率的に使用するLockBitsには、基本的に画像をロックしてから、安全でないポインタを使用してピクセルの値を取得する必要があります。これを行うためのコードは、ピクセル形式によって少し異なります。実際に32bpp形式で、青がLSBになっているとすると、コードは次のようになります。

for (int y = 0; y < bmpData.Height; ++y)
{ 
    byte* ptrSrc = (byte*)(bmpData.Scan0 + y * bmpData.Stride);
    int* pixelPtr = (int*)ptrSrc;

    for (int x = 0; x < bmpData.Width; ++x)
    {
        Color col = Color.FromArgb(*pixelPtr);

        if (col == ColorToFind) return new Point(x, y);

        ++pixelPtr; //Increate ptr by 4 bytes, because it is int
    }
}

いくつかの発言:

  • 各行について、Scan0+ストライド値を使用して新しいptrSrcが計算されます。これは、ポインタを増やすだけでは失敗する可能性があるためStride != bpp * widthです。
  • 青いピクセルはLSBとして表され、アルファはMSBとして表されると仮定しましたが、これらのGDIピクセル形式は奇妙だったため、そうではなかったと思います。メソッドを使用する前にFromArgb()
  • ピクセル形式が24bppの場合、明らかな理由でintポインターを使用して1(4バイト)増やすことができないため、少し注意が必要です。
于 2012-02-12T17:33:19.727 に答える