Pixel farbe suchen[Pixelsearch]
-
nabend
ich wollte eine Funktion basteln, die die Position einer sich auf dem Bildschirm befindene Farbe zurück gibt. also eine Art Pixelsearch
Ich bin neu in cpp und habe mit winapi zum Teil noch ein paar Probleme und hoffe, dass ihr mir helfen könnt...
solange es noch nicht so funktioniert wie ich will, hat es kein sinn das in eine funktion zu tun, deshalb hab ich ersteinmal in der main() funktion gelassenMeine Idee(durch hilfe aus dem c++ bereich hier im forum):
Die Pixel des Desktop's in einer Bitmap zu speichern und dann auf byte ebene die rgb farben auslesen und mit einer anderen farbe zu vergleichen... Nur irgentwie habe ich das untrügliche gefühl, dass ich bei der Bitmap erstellung etwas falsch gemacht habe, da die benötigten farbwerte leider nicht in der memory variable abgelegt werden.. Könnt ihr mich auf die richtige Spur bringen oder mir sagen wo der fehler liegt?#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"); }
Anmerkung: Ich habe mich auch schon mit getpixel in eienr forschleife probiertm was zwar fnktioniert hat, aber viel zu langsam war... ich würde gerne unter 10 milisekunden brauchen..
Danke schon einmal für jegliche Hilfe!!
-
Ein paar Anmerkungen:
Wenn du die Variable rot vergleichst (for-Schleife), musst du sie vorher initialisieren.
Erzeugst du da nicht eine 32-Bit-DIB? In der Schleife inkrementierst du memory aber nur 3 Mal pro Iteration, nicht 4 Mal...
Ist es nicht schlecht, memDC zu zerstören, wenn es noch selektiert ist (bin da nicht mehr so im Thema drin und nicht sicher...).
Du solltest etwas mehr Rückgabewerte prüfen! Beispielsweise liefert BitBlt doch eine Rückgabe, ob es geklappt hat...
-
Erzeugst du da nicht eine 32-Bit-DIB? In der Schleife inkrementierst du memory aber nur 3 Mal pro Iteration, nicht 4 Mal...
1 mal wird doch jedesmal beim header inkrementiert....
Ist es nicht schlecht, memDC zu zerstören, wenn es noch selektiert ist
sollte doch eigentlich nicht von belang sein.. es endsteht ja kein error und die zuweisung ist bereits erfolgt..
Wenn du die Variable rot vergleichst (for-Schleife), musst du sie vorher initialisieren.
Hab ich doch, in Zeile 12 mit: short rot, gruen, blau;
Du solltest etwas mehr Rückgabewerte prüfen! Beispielsweise liefert BitBlt doch eine Rückgabe, ob es geklappt hat...
BitBlt kenn ich bis jetzt noch nicht (wie gesagt, hab erst vor kurzem angefangen) werd's mir aber demnächst mal anschauen.
Danke aber immerhin, dass du geantwortet hast
Hat sonst noch wer Ideen?
-
Deathly Assassin schrieb:
1 mal wird doch jedesmal beim header inkrementiert....
Richtig, hab ich übersehen.
Deathly Assassin schrieb:
Hab ich doch, in Zeile 12 mit: short rot, gruen, blau;
Nein. Du deklarierst da zwar deine Variablen, initialisierst sie aber nicht (du weist ihnen keinen Wert zu). Was an den Stellen im Speicher steht, ist purer Zufall. Im schlimmsten, denkbaren Fall hat eine der Variablen zufällig den Wert 255 bzw. 0, und deine for-Schleife wird nicht ausgeführt. Unwahrscheinlich, aber möglich.
-
hmmm.... und was wäre dein vorschlag, wie ich den variablen die werte richtig zuweisen könnte?
übrigens sollte der teil, der im header übergangen wird der alpha teil sein.... für mich ist das aber nicht interressant^^
-
hat absolut keiner eine Idee?
-
// biBitCount = 32; for (int a=0; a<(dx*dy); a++) { if (*(COLORREF*)memory[a] == RGB(suchende r,g,b)) { // gefunden } }
-
hast du das bitmap schon als datei gespeichert ung geguckt ob überhaupt etwas drin ist ?
-
@sapero
Hmmm immer wenn ich etwas zwischen den Mengenklammern angebe (also die if abfrage gemacht wird) kommt die nachricht, dass mein compiledes script einen Fehler festgestellt hätte und ob dieser an microsoft gesendet werden solle O.o liegt das an Dev-C++? Compiler macht jedenfalls keine Zicken..
@tipp
.... ja, es ist was drin, aber es endsteht nur eine farbenfrohe bildschirmdiagonale
hier der Code zum prüfen:#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; 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; 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; /* // biBitCount = 32; for (i=0; i<(dx*dy); i++) { if (*(COLORREF*)memory[i] == RGB(255,255,0)) { // gefunden x= i*8/info.bmiHeader.biBitCount/dy; y= i*8/info.bmiHeader.biBitCount/dx; SetPixel(Bildschirm, x, y, 0x000000) } }*/ for(i = 0; i < tbytes; ++i) { rot=memory[++i]; //rot gruen=memory[++i]; //grün blau=memory[++i]; //blau x= i*8/info.bmiHeader.biBitCount/dy; y= i*8/info.bmiHeader.biBitCount/dx; SetPixel(Bildschirm, x, y, RGB(rot, gruen, 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"); }
-
rot=memory[++i]; //rot gruen=memory[++i]; //grün blau=memory[++i]; //blau
Das ist falsch:
1. zuerst ist blau, grün, rot, und dann alpha/unused.
2. teil = memory[++i] // ein Byte ist weg (memory[0])
Ich habe immer definiert mein Zeiger als RGBQUAD* für 32-bit DIB's:RGBQUAD *memory; CreateDIBSection(..., (void**)&memory);
RGBQUAD ist das selbe wie COLORREF, nur die einzelne Bytes haben Namen.
-
1. zuerst ist blau, grün, rot
danke
hab vergessen das es BGR statt RGB ist..
2. teil = memory[++i] // ein Byte ist weg (memory[0])
memory[0]=Alpha Kanal
memory[1]=Blau Kanal
memory[2]=Grün Kanal
memory[3]=Rot KanalRGBQUAD ist das selbe wie COLORREF, nur die einzelne Bytes haben Namen
und welchen vorteil/nachteil hat das für mich?
man kommt in die schleife, i ist am anfang 0, wird auf 1 gesetzt und dann der memory[1] wert in der variable blau gespeichert.
Am header wird dann immer der Alpha kanal übergangen....
Allerdings stimmt meine rückrechnung auch nicht... Es ist jedesmal so, dass ich wenn ich x berechne, y meine desktophöhe sein müsste und wenn ich y berechne müsste x meine desktopweite sein....
Die rückrechnung von x und y ist also falsch, ich weiß aber leider nicht, wie ich es sonst umsetzen kann....
Hat wer von euch schonmal ein erfolgreiches script zum bitmap speichern oder durchsuchen gemacht?
-
Zuerst sorry für die inkomplete COLORREF = RGBQUAD, da R und B sind vertauscht. Hier ist die Belohnung:
int main() { int x=1, y=1, i; int dx = GetSystemMetrics(SM_CXSCREEN); int dy = GetSystemMetrics(SM_CYSCREEN); BITMAPINFO info = {0}; info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biWidth = dx; info.bmiHeader.biHeight = dy; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 32; // 32:RGBQUAD; 24:RGBTRIPLE HBITMAP bitmap; RGBQUAD* memory; HDC hdcDesktop = GetDC(0); bitmap = CreateDIBSection(hdcDesktop, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0); if(!bitmap || !memory) return ReleaseDC(0, hdcDesktop); HDC hdcMemory = CreateCompatibleDC(hdcDesktop); HGDIOBJ oldbitmap = SelectObject(hdcMemory, bitmap); BitBlt(hdcMemory, 0, 0, dx, dy, hdcDesktop, 0, 0, SRCCOPY); // test { SetPixel(hdcMemory, 133, 144, RGB(255,255,1)); } SelectObject(hdcMemory, oldbitmap); DeleteDC(hdcMemory); //ReleaseDC(0, hdcDesktop); später int tbytes = dx * dy; // biBitCount = 32; for (i=0; i<tbytes; i++) { RGBQUAD *p = &memory[i]; if (RGB(p->rgbRed, p->rgbGreen, p->rgbBlue) == RGB(255,255,1)) { y = i / dx; x = i % dx; y = dy - y - 1; // nur wenn info.bmiHeader.biHeight ist positiv Ellipse(hdcDesktop, x-32, y-32, x+32, y+32); TCHAR info[64]; _stprintf(info, TEXT("gefunden at %dx%d"), x, y); MessageBox(0, info, 0, 0); break; } } DeleteObject(bitmap); ReleaseDC(0, hdcDesktop); return 0; }
-
danke
hat mir sehr geholfen
-
Hmm.... ich habe das gefühl, dass beim häufigerem aufrufen ein GDI lag endsteht, da die cpu lastung zwar extrem niedrig ist, der ganze pc jedoch anfängt zu hacken/laggen was extremer wird, je länger ich das Programm laufen lasse...
Ich habe also den verdacht, dass die bitmap nicht richtig gelöscht/released wird...
habe schon einiges Probiert um dieses Problem zu beheben, komme aber zu keiner wirksamen lösung...
Tut mir leid, das ich euch immernoch damit belästige^^
-
GDI Leaks kannst du einfach mit dem Task Manager aufspüren. Da kannst du in den Optionen die eingeblendeten Spalten einstellen, u.a. auch GDI Handles.