Найти пиксель по точке возврата цвета - PullRequest
0 голосов
/ 12 февраля 2012

Мне нужно найти точки / кординаты (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);
}

Ответы [ 2 ]

2 голосов
/ 12 февраля 2012

Вы не прекратили использовать 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, потому что линии хранятся в перевернутом виде в растровом изображении.И не возвращайте новую точку (0, 0) при ошибке, это правильный пиксель.

1 голос
/ 12 февраля 2012

В вашем коде есть несколько ошибок:

  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
    }
}

Несколько замечаний:

  • Для каждой строки новый ptrSrc вычисляется с использованием значения шага Scan0 +.Это потому, что простое увеличение указателя может не сработать, если Stride != bpp * width, что может иметь место.
  • Я предположил, что синий пиксель представлен как LSB, а альфа как MSB, что, я думаю, не имело место,потому что эти форматы пикселей GDI были .. странными;), просто убедитесь, что вы проверили, если это не так, обратные байты, прежде чем использовать метод FromArgb().
  • Если ваш формат пикселей 24bpp, это немногоболее хитроумно, потому что вы не можете использовать указатель int и увеличить его на 1 (4 байта) по понятным причинам.
...