Pixelsuche, TBitmap mit Scanline



  • naja, nur dass dir eben noch der wichtige Screenshot Teil fehlt...den willst du offenbar übersehen. 🙂

    greetz KN4CK3R



  • Hallo

    VergissEs schrieb:

    0 und NULL sind nicht das selbe NULL ist nichts und
    du willst ja einen Screenshot vom Desptop und der hat das Handel 0.

    Das stimmt nicht, 0 und NULL sind in C++ identisch, in C ist NULL als Zeiger auf 0 definiert. In diesem konkreten Fall mit dem Handle führt jedenfalls beides zum gleichen Ziel : GetDC bekommt einen Zeiger auf 0, denn "0" wird impliziet auf void* gecastet.

    Hier die konkrete Implemetation von NULL im Builder aus der Datei _null.h :

    #ifndef NULL
    #  if defined(__cplusplus) || defined(_Windows)
    #    define NULL 0
    #  else
    #    define NULL ((void *)0)
    #  endif
    #endif
    

    bis bald
    akari

    /edit akari : Korrektur siehe Post von MFK



  • KN4CK3R schrieb:

    naja, nur dass dir eben noch der wichtige Screenshot Teil fehlt...den willst du offenbar übersehen. 🙂

    greetz KN4CK3R

    😃

    HDC HWindowDC = GetWindowDC(Form1->Handle);
        BitBlt(Image1->Picture->Bitmap->Canvas->Handle, 0, 0,
               Image1->Picture->Bitmap->Width, Image1->Picture->Bitmap->Height,
               HWindowDC, 0, 0,
               SRCCOPY);
        ReleaseDC(Form1->Handle, HWindowDC);
    

    Danke.

    Ich habe aber noch eine Frage. Ist BitBlt nicht nur um die Bitmap anzeigen zu lassen? Also brauch ich es für die Scanline garnicht?



  • akari schrieb:

    0 und NULL sind in C identisch, in C++ ist NULL als Zeiger auf 0 definiert.

    Andersrum 😉



  • Könnt ihr bitte bei der Thema bleiben und mir den letzen Tipp geben?^^

    Ich habe jetzt so aufgebaut:

    int iSizeW = GetSystemMetrics( 0 );
    int iSizeH = GetSystemMetrics( 1 );
    HDC dc;
    HDC cdc;
    HBITMAP hBitmap;
    int scanx=0, scany=0;
    TRGBTriple *xpix;
    TRGBTriple *ypix;
    
    DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
       while(1)
       {
    	  if(scanthread==true)
    	  {
    	   Graphics::TBitmap *bmp = new Graphics::TBitmap();
    		dc = GetDC(NULL);
    		hBitmap = CreateCompatibleBitmap(dc, iSizeW, iSizeH);
    	 bmp->Height=iSizeH;
    	 bmp->Width=iSizeW;
    	 bmp->PixelFormat=pf24bit;
    	 bmp->Handle=hBitmap;
    
    	   for(scanx=0; scanx < bmp->Width; scanx++)
    		{
    		 ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    		if(ypix->rgbtBlue == 191 && ypix->rgbtGreen==89 && pix->rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    		for(scany=0; scany<bmp->Height; scany++)
    			{
    
    			}
    		}
    		ReleaseDC(0,dc);
    		ReleaseDC(0,cdc);
    		delete bmp;
    	  }
    	  Sleep(10);
       }
    

    Ist es so richtig? Ansonsten fehlt mit der Teil mit BitBlt, den ich nicht ganz verstanden hab. Kann mir vielleicht jemand erklähren? Weiß gerade nicht wie ich es ohne Image1->Picture->Bitmap->Canvas->Handle einsetzen soll.



  • ja der BitBlt Teil ist ja grad der wichtige Teil. BitBlt kopiert die Bilddaten von der Quelle zum Ziel.

    greetz KN4CK3R



  • DWORD WINAPI ScanFunc( LPVOID lpParam )
    {
       while(1)
       {
    	  if(scanthread==true)
    	  {
    	   Graphics::TBitmap *bmp = new Graphics::TBitmap();
    		dc = GetDC(NULL);
    		hBitmap = CreateCompatibleBitmap(dc, iSizeW, iSizeH);
    	 bmp->Height=iSizeH;
    	 bmp->Width=iSizeW;
    	 bmp->PixelFormat=pf24bit;
    	 bmp->Handle=hBitmap;
    	 cdc = GetWindowDC(0);
    	 BitBlt(bmp->Canvas->Handle, 0, 0,
    		   bmp->Width,  bmp->Height,
    		   cdc, 0, 0,
    		   SRCCOPY);
    
    	   for(scanx=0; scanx < bmp->Width; scanx++)
    		{
    		 ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    		if(ypix->rgbtBlue == 191 && ypix->rgbtGreen==89 && ypix->rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    		for(scany=0; scany<bmp->Height; scany++)
    			{
    
    			}
    		}
    		ReleaseDC(0,dc);
    		ReleaseDC(0,cdc);
    		delete bmp;
    	  }
    	  Sleep(10);
       }
    }
    

    Wenn ich es richtig verstanden hab, dann muss es so gehen oder?
    Das Problem ist, ich kriege beim starten des Threads wieder die Fehlermeldung. Und kann deshalb nicht testen. Aber wieso kommt der Fehler wenn sich diesmal alles normal abläuft?



  • Debugger oder den Teil erstmal auskommentieren und schauen ob dein Screenshot jetzt stimmt.

    greetz KN4CK3R



  • Der Fehler wird durch GetDC(0) erzeugt.
    Wie soll ich es ohne GetDC(0) testen?

    EDIT: Einmal hat es geklappt. Hab sogar dann die bmp auf der Image gesehn aber, dann kam gleich eine Fehlemeldung "EOutOfResources... "falsche parameter".



  • du willst doch bloß meinen Code sehen 😉

    Graphics::TBitmap *s = new Graphics::TBitmap();
    TCanvas *canvas = new TCanvas();
    canvas->Handle = GetWindowDC(GetDesktopWindow());
    
    TRect source;
    GetWindowRect(GetDesktopWindow(),(LPRECT)&source);
    s->Width = source.Right;
    s->Height = source.Bottom;
    s->Canvas->CopyRect(s->Canvas->ClipRect,canvas,source);
    
    //mach was mit s
    
    s->FreeImage();
    delete s;
    

    greetz KN4CK3R



  • KN4CK3R schrieb:

    du willst doch bloß meinen Code sehen 😉

    Graphics::TBitmap *s = new Graphics::TBitmap();
    TCanvas *canvas = new TCanvas();
    canvas->Handle = GetWindowDC(GetDesktopWindow());
    
    TRect source;
    GetWindowRect(GetDesktopWindow(),(LPRECT)&source);
    s->Width = source.Right;
    s->Height = source.Bottom;
    s->Canvas->CopyRect(s->Canvas->ClipRect,canvas,source);
    
    //mach was mit s
    
    s->FreeImage();
    delete s;
    

    greetz KN4CK3R

    Danke, aber wenn du so ungerne deine codes Zeig, hättest sagen gleich sagen können, dass da Canvas hin muss oder etwas ähnlich beschreiben, ich habe schon Beispiele gesehen, aber dachte, man braucht es nur wenn man als Datei speichern will.
    Abgesehn davon muss ja irgendwo stehen wie es geht . 😉

    EDIT: Den Fehler kommt immer noch.



  • der Canvas Teil ist der VCL Ersatz für den BitBtl-Aufruf. Probier den Code mal außerhalb von deinem Timer und schau obs dann funktioniert.

    greetz KN4CK3R



  • Hab es bei einen Button OnClick rein, hilft nicht, ich kriege immer die Fehlermeldung:

    Im Projekt xxx.exe ist eine Exception der Klasse EInvalidGraphicOperation mit der Meldung "Bereichsüberschreitung bei Zeilenindex" aufgetreten.
    
    Graphics::TBitmap *bmp = new Graphics::TBitmap();
    	   TCanvas *canvas = new TCanvas();
    		canvas->Handle = GetWindowDC(GetDesktopWindow());
    
    		TRect source;
    	GetWindowRect(GetDesktopWindow(),(LPRECT)&source);
    	bmp->Width = source.Right;
    	bmp->Height = source.Bottom;
    	bmp->Canvas->CopyRect(bmp->Canvas->ClipRect,canvas,source);
    
    	  //ForLoL->Image1->Picture->Bitmap=bmp;
    
    	   for(scanx=0; scanx <= bmp->Width; scanx++)
    		{
    
    		 ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    	   if(ypix->rgbtBlue == 100 && ypix->rgbtGreen==255 && ypix->rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    		for(scany=0; scany <= bmp->Height; scany++)
    			{
    
    			}
    		}
    		bmp->FreeImage();
         delete canvas;
    		delete bmp;
    


  • ich seh nirgendswo ne Definition von scany vor der Schleife (die übrigends keinen Sinn ergibt). Schau dir nochmal an, wie du mit RGBTriple richtig arbeitest.

    greetz KN4CK3R



  • KN4CK3R schrieb:

    ich seh nirgendswo ne Definition von scany vor der Schleife (die übrigends keinen Sinn ergibt). Schau dir nochmal an, wie du mit RGBTriple richtig arbeitest.

    greetz KN4CK3R

    Global:

    int scanx=0;
    int scany=0;
    TRGBTriple *xpix;
    TRGBTriple *ypix;
    

    Hab die Schleifen geändert:

    for(scanx=0; scanx < bmp->Width; scanx++)
    		{
    		for(scany=0; scany < bmp->Height; scany++)
    			{
    			ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    			 if(ypix->rgbtBlue == 100 && ypix->rgbtGreen==255 && ypix->rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    			}
    		}
    

    So wie ich es verstehe:
    Die x Schleife fängt an mit 0, trifft dann auf die y Schleife. Y läuft dann bis es aus der Bildschirmrand trifft, dabei wird jedes Pixel von ScanLine überprüft und TRGBTriple gibt halt die 3 Farben an ypix weiter, bei der if abfrage wird jede Farbe überprüft um Herauszufinden ob die gewünschte Farbe sich gerade auf dem pixel befindet. Wenn Y-Schleife den Bildschirm erreicht läuft die X-Schleife um 1pixel weiter. Und so läuft alles bis X-Schleife über den Rand kommt.



  • nö, die linke Pixelreihe wird von oben nach unten bmp->Width mal durchsucht, zur Seite geht da nichts

    greetz KN4CK3R



  • for(scanx=0; scanx < bmp->Width; scanx++)
    		{
    		 xpix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scanx])
    		for(scany=0; scany < bmp->Height; scany++)
    			{
    			ypix = reinterpret_cast<TRGBTriple *>(bmp->ScanLine[scany]);
    			 if(ypix->rgbtBlue == 100 && ypix->rgbtGreen==255 && ypix->rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    			}
    		}
    

    😕
    Ich glaube da fehlt noch was, werde mal darüber schlaffen, fällt mir jetzt nicht ein.



  • ich hab schonmal gesagt, du sollst dir anschauen, was ScanLine macht. Da kommt ein Pointer auf eine Zeile von links nach rechts zurück, die kannst du einfach als Array benutzen.

    Ermöglicht einen indizierten, zeilenweisen Zugriff auf Pixel.

    greetz KN4CK3R



  • TRGBTriple *xpix; //Global
    TRGBTriple *ypix; //Global
    
    for(scany=0; scany < bmp->Height; scany++)
    		{
    		ypix = (TRGBTriple *)bmp->ScanLine[scany];
    		for(scanx=0; scanx < bmp->Width; scanx++)
    			{
    			xpix = (TRGBTriple *)bmp->ScanLine[scanx];
    
    			 if(ypix[scanx].rgbtBlue == 100 && ypix[scanx].rgbtGreen==255 && ypix[scanx].rgbtRed ==255)
    			 {
    				MessageBox(0,"Gefunden","test1",MB_OK);
    			 }
    			}
    		}
    

    So ungefähr?



  • nein, du brauchst nur einen Aufruf von ScanLine, danach den Pointer der zurückkommt mit x als Array benutzen. Den zweiten Aufruf kannst du wieder rauslöschen, der wird nicht gebraucht.

    greetz KN4CK3R


Anmelden zum Antworten