Pixel farbe suchen [Pixelsearch]



  • Heyho!
    Ich bin noch einigermaßen neu in C++ und schier am verzweifeln auf der suche nach einer Methode eine bestimmte Pixelfarbe in einem bestimmten Bereich des Bildschirmes zu finden.
    Ich habe es bereits mit GetPixel in einer for schleife probiert, jedoch braucht diese Methode ca. 5 sekunden für den ganzen bildschirm, was mit zu langsam ist 😉

    Ich weiß, das es methoden gibt, die den kompletten bildschirm in ca. 3-4 milisekunden abgesucht haben, doch habe ich nicht den hauch einer ahnung, wie das bewerkstelligt wird.

    könnt ihr mir weiterhelfen?

    (hier mal die source, die ich bis jetzt verwendet habe:)

    int x=1, y=1, color;
    bool found=false;
    
    HDC Bildschirm;
    
    Bildschirm = CreateDC("DISPLAY",NULL,NULL,NULL); 
    
     for (y=1; y<=1024 && found==false; ++y)
     {
         for (x=1; x<=1280 && found==false; ++x)
         {
         	color=GetPixel(Bildschirm, x, y);
            if (color==16711935)//
               found=true;		
         }
     }
    
    cout << x << ", " << y;
    


  • 1. Schon mal als Release kompiliert?

    2. Ich würde den DC erstmal in den Speicher (z.B. als Bitmap) speichern und da dann auf Byte-Ebene suchen.
    Das ist sicher schneller als jedes mal eine Funktion aufzurufen.



  • Zudem wäre es sicher performanter, du würdest die Funktion beenden, sobald etwas gefunden wurde, anstatt weiter zu suchen und in jeder Iteration auf found zu prüfen.



  • @Nexus:
    danke, hab das script angepasst und es ist schon schneller geworden, jedoch immer noch weit endfernt von den 3-4 milisekunden.

    Ich bin grade am googlen und schaun wie ich ein bmp screen mache und da auslese...
    hier mal der angepasste code... meld mich wieder wenn ich die Bmp variante probiert habe und bin natürlich für jeden weiteren vorschlag dankbar 😃

    int x=1, y=1;
    short color;
    
    HDC Bildschirm;
    
    Bildschirm = CreateDC("DISPLAY",NULL,NULL,NULL); 
    
     for (y=1; y<=1024 && color!=16711935; ++y)
     {
              for (x=1; x<=1280 && color!=16711935; ++x)
    			color=GetPixel(Bildschirm, x, y);		
     }
    


  • 😞
    Ich werde irgentwie nicht so wirklich fündig...
    desweiteren hab ich auch heute erst mit den WinApi funktionen angefangen und tu mich noch etwas schwer...

    könntest du ein beispiel code posten, wie man ein DC in einem bmp speichert?
    (und ist dies dann wirklich unter 10 ms schnell?)
    Außerdem muss man dann doch die pixel aus dem bmp auslesen und vergleichen... dauert das denn nicht genauso lange?

    tut mir leid, bin halt noch ein totaler einsteiger^^



  • http://www.google.de/search?hl=de&q=screenshot+winapi+bmp&btnG=Google-Suche&meta=
    

    Für deine Aufgabe dürfte das Codestück tun:

    //http://www.c-plusplus.net/forum/viewtopic-var-t-is-138375-and-highlight-is-screenshot+desktop.html
     // get desktop window (but can be any window)
     HWND capture = GetDesktopWindow();
     if(!IsWindow(capture)) return 1;
    
     // get window dimensions
     RECT rect;
     GetWindowRect(capture, &rect);
    
     size_t dx = rect.right - rect.left;
     size_t dy = rect.bottom - rect.top;
    
     // create BITMAPINFO structure
     // used by CreateDIBSection
     BITMAPINFO info;
     info.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
     info.bmiHeader.biWidth         = dx;
     info.bmiHeader.biHeight        = dy;
     info.bmiHeader.biPlanes        = 1;
     info.bmiHeader.biBitCount      = 32; //24 würde weniger Speicher brauchen aber das auslesen der Farbinformationen etwas komplizierter machen.
     info.bmiHeader.biCompression   = BI_RGB;
     info.bmiHeader.biSizeImage     = 0;
     info.bmiHeader.biXPelsPerMeter = 0;
     info.bmiHeader.biYPelsPerMeter = 0;
     info.bmiHeader.biClrUsed       = 0;
     info.bmiHeader.biClrImportant  = 0;
    
     // a bitmap handle and a pointer its bit data
     HBITMAP bitmap = 0;
     BYTE*   memory = 0;
    
     // create bitmap
     HDC device = GetDC(capture);
     bitmap = CreateDIBSection(device, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
     ReleaseDC(capture, device);
     if(!bitmap || !memory) return 1;
    //...
    int tbytes = dx * dy * info.bmiHeader.biBitCount / 8; // (((24*dx + 31) & (~31))/8)*dy; falls du biBitCount oben auf 24 gesetzt hast
    [Edit]// die Zeilen sollten auch noch dazu wenn du fertig bist:
    
     // delete bitmap
     DeleteObject(bitmap);
     bitmap = 0;
     memory = 0;
    

    Habs nicht ausprobiert aber ich denke dass das soweit funktionieren müsste.
    tbytes ist die Anzahl der Bytes des memory-Datenblocks.
    So kommst du dann an die Farbinfos:

    for( int i = 0; i < tbytes; i+=4 )
    {
     memory[i+1] //rot
     memory[i+2] //grün
     memory[i+3] //blau
    }
    

    Ich würde sagen dass das auf alle Fälle schneller ist als GetPixel, obs 10 ms schnell ist musst du schon selbst probieren (Compiler auf Release stellen!!!).

    Deine Frage hat übrigens wenig mit reinem C++ zu tun. Ein netter Mod wird dich sicher ins Winapi-Forum verschieben.



  • danke, dass hat mir sehr geholfen und die geschwindigkeit liegt jetzt bei ca. 2 milisekunden 😃

    2 letzte frage hätte ich noch, bevor ich euch erst einmal in ruhe lasse ;D:
    wie stellt man einen compiler auf release? ich benutze Blodsheed Dev-C++ und habe da die compiler optionen durchgeguckt, bin aber nicht fündig geworden... muss ich mir dafür visual studios/einen Prozessor spezifischen compiler holen?

    und muss ich diese zeile hier machen:

    int tbytes = dx * dy * info.bmiHeader.biBitCount / 8;
    

    da ich ja die koordinaten des pixels haben möchte... kann ich da dann meine obrige for schelfie mit dx & dy nehmen?



  • 1. Bloodsheed Dev-C++ wird seit 2005 nicht mehr weiterentwickelt und ist dementsprechend veraltet.
    Da du am Anfang wohl ohnehin nur Winapi machen wirst empfehle ich dir mal die FAQ in dem entsprechenden Unterforum durchzulesen. Da steht auch wo du kostenlos eine aktuelle Entwicklungsumgebung herbekommen kannst.

    2. Diese Zeile sagt dir bloß wie groß der Block von "memory" ist.
    Du könntest die eine for-Schleife natürlich in 2 umbauen und den Index für das Array bei jedem Schleifendurchlauf neu berechnen.
    Für die Laufzeit wäre es aber besser(wenn auch nicht soooo viel) wenn du nur einmal im Trefferfall von i auf x und y zurückrechnen würdest.

    Für welche Variante du dich entscheidest und wie der entsprechende Quellcode aussieht überlasse ich jetzt aber mal dir. 😉



  • Dank dir....

    hmm.....

    es scheint so, als hätte die array "memory" in jedem Ellemt nur eine 0 stehen, was mich einen Fehler beim Bitmap erstellen vermuten lässt.

    bei den bitmap erstellungen habe ich eigentlich nichts verändert, trotzdem werde ich sie vorsichtshalber posten:

    HDC Bildschirm;
    
    	Bildschirm = CreateDC("DISPLAY",NULL,NULL,NULL); 
    	HWND hwnd = GetDesktopWindow();
    
    	if(!IsWindow(hwnd)) return 1;
    
    	RECT rect;
        GetWindowRect(hwnd, &rect);
        size_t dx = rect.right - rect.left;
        size_t dy = rect.bottom - rect.top;
    
               BITMAPINFO info;
               info.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
               info.bmiHeader.biWidth         = dx;
               info.bmiHeader.biHeight        = dy;
               info.bmiHeader.biPlanes        = 1;
               info.bmiHeader.biBitCount      = 32; //24 würde weniger Speicher brauchen aber das auslesen der Farbinformationen etwas komplizierter machen.
               info.bmiHeader.biCompression   = BI_RGB;
               info.bmiHeader.biSizeImage     = 0;
               info.bmiHeader.biXPelsPerMeter = 0;
               info.bmiHeader.biYPelsPerMeter = 0;
               info.bmiHeader.biClrUsed       = 0;
               info.bmiHeader.biClrImportant  = 0;
    
                HBITMAP bitmap = 0;
                BYTE*   memory = 0;
    
                HDC device = GetDC(hwnd);
                bitmap = CreateDIBSection(device, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
                ReleaseDC(hwnd, device);
                if(!bitmap || !memory) return 1;
                //...
                int tbytes = dx * dy * info.bmiHeader.biBitCount / 8;
    
                for(i = 0; i < tbytes && (rot!=222 || gruen!=255 || blau!=214); ++i)
                {
                rot=memory[++i]; //rot
                gruen=memory[++i]; //grün
                blau=memory[++i]; //blau
                }
    

    ... meine schleife und rückrechnung sieht so aus:

    for(i = 0; i < tbytes && (rot!=222 || gruen!=255 || blau!=214); ++i)
    {
    rot=memory[++i]; //rot
    gruen=memory[++i]; //grün
    blau=memory[++i]; //blau
    }
    
    DeleteObject(bitmap);//die bitmap wieder freigeben
    bitmap = 0;//
    memory = 0;//
    
    //i= 1280*1024*32/8
    x= i*8/info.bmiHeader.biBitCount/dy;
    y= i*8/info.bmiHeader.biBitCount/dx;
    

    Die if abfrage, ob die farbe gefunden wurde, oder ob es einfach nur durchgelaufen ist, habe ich weggelassen...
    Einen compiler error/warnung gibt es übrigens nicht.



  • Ich habe den Code wie gesagt nicht getestet.
    Wenn er nicht so funktioniert wie gewünscht dann verwende doch einen von den ungefähr 200 anderen Vorschlägen die google ausspuckt.



  • tut mir ehrlich leid und du darfst mich von mir aus auch als google noob beschimpfen, aber leider finde ich dort nur den einen, den du schon als beispiel gepostet hast und dieses thread (ich weiß, ich bin grade mega anstrengend... sry 😞 ).... der rest ist leider mehr oder weniger nicht zu gebrauchen....

    Mein volles script sieht momentan so aus:

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        //GetWindowRect(hwnd, &rect);
    
        Sleep(1000);
        int x=1, y=1, i;
        short rot, gruen, blau;
    
        HDC Bildschirm;
    
    	Bildschirm = CreateDC("DISPLAY",NULL,NULL,NULL); 
    	HWND hwnd = GetDesktopWindow();
    
    	if(!IsWindow(hwnd)) return 1;
    
    	RECT rect;
        GetWindowRect(hwnd, &rect);
        size_t dx = rect.right - rect.left;
        size_t dy = rect.bottom - rect.top;
    
               BITMAPINFO info;
               info.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
               info.bmiHeader.biWidth         = dx;
               info.bmiHeader.biHeight        = dy;
               info.bmiHeader.biPlanes        = 1;
               info.bmiHeader.biBitCount      = 32; //24 würde weniger Speicher brauchen aber das auslesen der Farbinformationen etwas komplizierter machen.
               info.bmiHeader.biCompression   = BI_RGB;
               info.bmiHeader.biSizeImage     = 0;
               info.bmiHeader.biXPelsPerMeter = 0;
               info.bmiHeader.biYPelsPerMeter = 0;
               info.bmiHeader.biClrUsed       = 0;
               info.bmiHeader.biClrImportant  = 0;
    
                HBITMAP bitmap = 0;
                BYTE*   memory = 0;
    
                HDC device = GetDC(hwnd);
                bitmap = CreateDIBSection(device, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
                ReleaseDC(hwnd, device);
                if(!bitmap || !memory) return 1;
                //...
    
                // blit the contents of the desktop (winDC)
                // to the bitmap (selected in memDC)
                HDC winDC = GetWindowDC(hwnd);
                HDC memDC = CreateCompatibleDC(winDC);
                SelectObject(memDC, bitmap);
                BitBlt(memDC, 0, 0, dx, dy, winDC, 0, 0, SRCCOPY);
                DeleteDC(memDC);
                ReleaseDC(hwnd, winDC);
    
            int tbytes = dx * dy * info.bmiHeader.biBitCount / 8;
            for(i = 0; i < tbytes && (rot!=255 || gruen!=255 || blau!=0); ++i)
            {
            rot=memory[++i]; //rot
            gruen=memory[++i]; //grün
            blau=memory[++i]; //blau
            }
    
            DeleteObject(bitmap);
            bitmap = 0;
            memory = 0;
    
            //i= 1280*1024*32/8
            x= i*8/info.bmiHeader.biBitCount/dy;
            y= i*8/info.bmiHeader.biBitCount/dx;
    
    //system("Pause");
    }
    

    aber funktionieren tut es leider immernoch nicht so, wie ich es mir erhofft hatte 😞


Anmelden zum Antworten