найти цвет на изображении в C # - PullRequest
7 голосов
/ 25 сентября 2010

Я наткнулся на это видео на YouTube здесь http://www.youtube.com/watch?v=Ha5LficiSJM, которое демонстрирует, что кто-то делает обнаружение цвета с помощью инфраструктуры AForge.NET.Я хотел бы дублировать то, что сделал этот автор, но я не уверен, как выполнить некоторую обработку изображения.

Может показаться, что среда AForge.NET позволяет вам извлекать из видеоисточника изображениев растровом формате.Мои вопросы: может ли кто-нибудь указать мне направление или дать какое-нибудь руководство о том, как опросить растровый объект, чтобы найти в нем определенные цвета?(например, если в течение X секунд на изображении присутствует «красный» или «фиолетовый», я бы хотел вызвать событие «ColorDetected» или около того ...)

Есть ли у кого-нибудь какие-либо предложения пос чего начать?

Спасибо,

-R.

РЕДАКТИРОВАТЬ: мне нужно было бы пройти весь растровый объект и опросить каждый пиксель для цвета?Вот так: http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.getpixel.aspx

Ответы [ 2 ]

16 голосов
/ 25 сентября 2010

Ну, вы всегда можете использовать метод GDI +.

Bitmap b = new Bitmap( "some path" );
Color x = b.GetPixel( x, y );

Однако GetPixel на самом деле довольно медленный. Попробуйте сначала, но если вам нужно отсканировать много относительно больших изображений, это может не сработать. В этом случае используйте LockBits, чтобы получить указатель на непрерывный кусок памяти. Затем вы можете быстро пройтись по изображению, но вы должны знать, как манипулировать указателями, хотя это не очень сложно.

РЕДАКТИРОВАТЬ: Использование LockBits для просмотра каждого пикселя:

Bitmap b = new Bitmap( "some path" );
BitmapData data = b.LockBits( new Rectangle( 0, 0, b.Width, b.Height ),
ImageLockMode.ReadOnly, b.PixelFormat );  // make sure you check the pixel format as you will be looking directly at memory

unsafe
{         
    // example assumes 24bpp image.  You need to verify your pixel depth
    // loop by row for better data locality
    for( int y = 0; y < data.Height; ++y )
    {
        byte* pRow = (byte*)data.Scan0 + y * data.Stride;
        for( int x = 0; x < data.Width; ++x )
        {
            // windows stores images in BGR pixel order
            byte r = pRow[2];
            byte g = pRow[1];
            byte b = pRow[0];

            // next pixel in the row
            pRow += 3;
        }
    }
}

b.UnlockBits(data);

Если ваши изображения дополняются в конце, вы можете использовать свойство BitmapData.Stride, чтобы перейти к началу каждой новой строки (в противном случае вы будете читать какой-то мусор и ваши смещения будут шуметь).

5 голосов
/ 25 сентября 2010

В дополнение к ответу Эда Свангрена с LockBits вы можете избежать указателей вместе.Если вы используете WPF (или имеете доступ к нему), вы можете сделать что-то вроде этого:

var bitmap = new BitmapImage(uri);

//Pixel array
byte[] pixels = new byte[width * height * 4]; //account for stride if necessary

bitmap.CopyPixels(..size, pixels, fullStride, 0); 

И теперь вы можете просто выполнить обычное сканирование массива с pixels без указателей.Этому фрагменту несколько лет, и он создан по проекту, в котором я разработал собственное решение AmbiLight, поэтому оно может быть довольно быстрым.Опять же, это несколько лет, поэтому новые классы, такие как WriteableBitmap и т. Д., Могут быть лучше и избегать копирования массива.В своем первоначальном решении я использовал указатели, но когда я понял, что в этом нет необходимости, я переключился.

...