Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Сравнение попиксельно зоны раб. стола с указ. *bmp


Автор: Travolta 27.11.2008, 12:04
День добрый.
Мне надо сравнить заданную зону(область) рабочего стола попиксельно с 
указанным *.bmp файлом.
Опишите пожалуйста алгоритм при котором можно произвести эту процедуру.
Желатьно с использованием ключевых операторов.
Спасибо.

Автор: diadiavova 27.11.2008, 17:08
Можно создать битмап, скопировать в него нужную часть экрана и сравнивать попмксельно два битмапа
Примерно так
Код

Bitmap bm = new Bitmap();
Graphics g = Graphics.FromImage(bm);
g.CopyFromScreen(...здесь параметры...);



И дальш bm сравнивать с образцом. Едимственная оговорка, при создании битмапа конструктор возможно прийдётся использовать другой, чтобы формат пикселя не отличался от от того, с которым картинка будет сравниваться.

Автор: jonie 28.11.2008, 01:43
скорость сравнения в GDI+ будет ужасной...
можно чуток ускорить.. варианты есть, например подсчет хеш суммы или игры с non-managed GDI....
вариант 2 (откуда-то честно сперт):
Код

/////////////////////////////////////////////////////////////////////////////
//
//  CompareBitmaps
//    Compares two HBITMAPs to see if they contain the same image
//
//  Parameters :
//    HBitmapLeft  [in] : The HBITMAP handles that are to be compared
//    HBitmapRight [in] :
//
//  Returns :
//    true if the bitmaps are the same
//    false if they are different
//
/////////////////////////////////////////////////////////////////////////////


bool CompareBitmaps(HBITMAP HBitmapLeft, HBITMAP HBitmapRight)
{
    if (HBitmapLeft == HBitmapRight)
    {
        return true;
    }

    if (NULL == HBitmapLeft || NULL == HBitmapRight)
    {
        return false;
    }

    bool bSame = false;

    HDC hdc = GetDC(NULL);
    BITMAPINFO BitmapInfoLeft = {0};
    BITMAPINFO BitmapInfoRight = {0};

    BitmapInfoLeft.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    BitmapInfoRight.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    if (0 != GetDIBits(hdc, HBitmapLeft, 0, 0, NULL, &BitmapInfoLeft, DIB_RGB_COLORS) &&
        0 != GetDIBits(hdc, HBitmapRight, 0, 0, NULL, &BitmapInfoRight, DIB_RGB_COLORS))
    {
        // Compare the BITMAPINFOHEADERs of the two bitmaps

        if (0 == memcmp(&BitmapInfoLeft.bmiHeader, &BitmapInfoRight.bmiHeader, 
            sizeof(BITMAPINFOHEADER)))
        {
            // The BITMAPINFOHEADERs are the same so now compare the actual bitmap bits

            BYTE *pLeftBits = new BYTE<BitmapInfoLeft.bmiHeader.biSizeImage>;
            BYTE *pRightBits = new BYTE<BitmapInfoRight.bmiHeader.biSizeImage>;
            BYTE *pByteLeft = NULL;
            BYTE *pByteRight = NULL;

            PBITMAPINFO pBitmapInfoLeft = &BitmapInfoLeft;
            PBITMAPINFO pBitmapInfoRight = &BitmapInfoRight;

            // calculate the size in BYTEs of the additional

            // memory needed for the bmiColor table

            int AdditionalMemory = 0;
            switch (BitmapInfoLeft.bmiHeader.biBitCount)
            {
            case 1:
                AdditionalMemory = 1 * sizeof(RGBQUAD);
                break;
            case 4:
                AdditionalMemory = 15 * sizeof(RGBQUAD);
                break;
            case 8:
                AdditionalMemory = 255 * sizeof(RGBQUAD);
                break;
            case 16:
            case 32:
                AdditionalMemory = 2 * sizeof(RGBQUAD);
            }

            if (AdditionalMemory)
            {
                // we have to allocate room for the bmiColor table that will be

                // attached to our BITMAPINFO variables

                pByteLeft = new BYTE[sizeof(BITMAPINFO) + AdditionalMemory];
                if (pByteLeft)
                {
                    memset(pByteLeft, 0, sizeof(BITMAPINFO) + AdditionalMemory);
                    memcpy(pByteLeft, pBitmapInfoLeft, sizeof(BITMAPINFO));
                    pBitmapInfoLeft = (PBITMAPINFO)pByteLeft;
                }

                pByteRight = new BYTE[sizeof(BITMAPINFO) + AdditionalMemory];
                if (pByteRight)
                {
                    memset(pByteRight, 0, sizeof(BITMAPINFO) + AdditionalMemory);
                    memcpy(pByteRight, pBitmapInfoRight, sizeof(BITMAPINFO));
                    pBitmapInfoRight = (PBITMAPINFO)pByteRight;
                }
            }

            if (pLeftBits && pRightBits && pBitmapInfoLeft && pBitmapInfoRight)
            {
                // zero out the bitmap bit buffers

                memset(pLeftBits, 0, BitmapInfoLeft.bmiHeader.biSizeImage);
                memset(pRightBits, 0, BitmapInfoRight.bmiHeader.biSizeImage);

                // fill the bit buffers with the actual bitmap bits

                if (0 != GetDIBits(hdc, HBitmapLeft, 0, 
                    pBitmapInfoLeft->bmiHeader.biHeight, pLeftBits, pBitmapInfoLeft, 
                    DIB_RGB_COLORS) && 0 != GetDIBits(hdc, HBitmapRight, 0, 
                    pBitmapInfoRight->bmiHeader.biHeight, pRightBits, pBitmapInfoRight, 
                    DIB_RGB_COLORS))
                {
                    // compare the actual bitmap bits of the two bitmaps

                    bSame = 0 == memcmp(pLeftBits, pRightBits, 
                        pBitmapInfoLeft->bmiHeader.biSizeImage);
                }
            }

            // clean up

            delete[] pLeftBits;
            delete[] pRightBits;
            delete[] pByteLeft;
            delete[] pByteRight;
        }
    }

    ReleaseDC(NULL, hdc);

    return bSame;
}



Автор: Travolta 28.11.2008, 11:43
diadiavova и jonie спасибо.

я стормозил. пишу на VС++.

jonie у меня        BYTE *pLeftBits = new BYTE<BitmapInfoLeft.bmiHeader.biSizeImage>;

эта строка и ей подобные выдаёт ошибку c:\documents and settings\duke\мои документы\visual studio projects\first2\first2.cpp(309): error C2446: '<' : no conversion from 'DWORD' to 'BYTE *'


как быть?

и ещё, извините за наглость, но всё же как скопировать зону экрана для данного случая ?

Автор: jonie 30.11.2008, 02:13
Цитата

Код

BYTE *pLeftBits = new BYTE<BitmapInfoLeft.bmiHeader.biSizeImage>;

это че за новомодный синтаксис такой ?

Автор: Travolta 30.11.2008, 19:09
ЭЭ.

Так это ж вроде из кода, который ты привёл.

Автор: Zakonnic 1.12.2008, 12:31
LockBits - штука как раз для таких случаев. Нууу... попробуйте создать отдельный проект с unsafe-методами и вставить что-то вроде этого:

Код

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace Utils
{
    public class MagicFeatures
    {
        unsafe public static bool CompareBmp(Bitmap bmp1, Bitmap bmp2, Rectangle rect)
        {   
            int width, height;
            width = rect.Width;
            height = rect.Height;
            int stride;
            PixelFormat pxl = bmp1.PixelFormat;

            BitmapData bmpData = bmp1.LockBits(rect, ImageLockMode.ReadOnly, pxl);
            IntPtr ptr = bmpData.Scan0;
            stride = bmpData.Stride;
            int offset = stride - 3 * width;
            int numbytes = width * (height) * 3 + offset * height;

            byte* bt1 = (byte*)ptr.ToPointer();

            // Далее фигарите такую же штуку для второго битмапа и сравниваете 
            // массивы побайтно (каждые 3 байта = RGB = 1 пиксель)

            // ...

         }

Чтобы код скомпилился, в свойсвах проекта надо разрешить ансейф-код. Потом можно получить битмап способом diadiavova и сравнить его с вашим, вызвав
bool result = Utils.MagicFeatures.CompareBmp(bmp1, bmp2, new Rectangle([координаты и размеры]));

ЗЫ. Код скопирован и слегка подправлен - если в таком виде не работает... ну придумайте что нибудь smile
 

Автор: Travolta 2.12.2008, 00:09
Zakonnic

Спасибо тебе за уделённое время.
Буду разбираться (для VC++)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)