Autor Wątek: Winapi prędkosć funkcji GetPixel()  (Przeczytany 8098 razy)

Offline kolarz3

  • Użytkownik

# Grudzień 08, 2013, 18:39:59
Otóż robię program który będzie obsługiwał myszkę. Problem polega na tym że muszę znać dane konkretnych pikseli. W tym celu korzystam z funkcji GetPixel(). Niestety oszacowałem że program taki w ciągu sekundy przeleci pętlę tylko 8 razy, zdecydowanie za mało. Czy jest jakiś sposób by to przyspieszyć co najmniej do 60 przebiegnięć na sekundę ?
#include <iostream>
#include <Windows.h>
#include <time.h>
#include <conio.h>
#include <list>
using namespace std;
void czekaj( float sekundy )
{
    clock_t koniec_czekania;
    koniec_czekania = clock() + sekundy * CLOCKS_PER_SEC;
    while( clock() < koniec_czekania ) { }
}
int main()
{
HDC hdc = GetDC( HWND_DESKTOP );
COLORREF kolor;

while(GetAsyncKeyState(0x31)==0){}
czekaj(0.2);
int r[4];
int r2[4];
int r3=0;
while(GetAsyncKeyState(0x31)==0)
{

kolor=GetPixel( hdc, 481, 287 );
r[0] = GetBValue( kolor );
kolor=GetPixel( hdc, 957, 291 );
r[1] = GetBValue( kolor );
kolor=GetPixel( hdc, 488, 530 );
r[2] = GetBValue( kolor );
kolor=GetPixel( hdc, 958, 530 );
r[3] = GetBValue( kolor );
kolor=GetPixel( hdc, 412, 325 );
r2[0] = GetBValue( kolor );
kolor=GetPixel( hdc, 896, 306 );
r2[1] = GetBValue( kolor );
kolor=GetPixel( hdc, 410, 570 );
r2[2] = GetBValue( kolor );
kolor=GetPixel( hdc, 883, 562 );
r2[3] = GetBValue( kolor );
r3++;
}
cout<<r3;
system("PAUSE");

}

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline MoHeR

  • Użytkownik

# Grudzień 08, 2013, 18:49:37
zatrzymujesz program na 200ms i licznik Ci dobija do 8 klatek na sekunde ? Niezle

Offline kolarz3

  • Użytkownik

# Grudzień 08, 2013, 19:17:33
Po 5 sec mam 40 przebiegnięć

Offline MoHeR

  • Użytkownik

# Grudzień 08, 2013, 21:15:14
Wiec napraw licznik FPS, a jeśli uważasz, ze dostajesz poprawny wynik, to chyba za wcześnie na liczenie FPS ;D przy zatrzymywania każdej klatki na 200 MS powinieneś dostać max 5fps. Nie ma prawa być więcej... Jeśli chcesz 60 FPS, to powinieneś zatrzymywać program na ~16ms (ale ten czas powinien być zależny od czasu trwania 1 klatki).

Offline Karol

  • Użytkownik

  • +2
# Grudzień 08, 2013, 21:46:22
zatrzymujesz program na 200ms i licznik Ci dobija do 8 klatek na sekunde ? Niezle
Funkcja czekaj() jest przecież poza pętlą...

Offline kolarz3

  • Użytkownik

# Grudzień 08, 2013, 22:33:51
Ja che po prostu to jakoś przyśpieszyć, by częściej pobierać wartość tych pikseli.

Offline Xirdus

  • Redaktor

# Grudzień 09, 2013, 01:24:38
Powiedz co chcesz tymi GetPixelami osiągnąć, to może łatwiej będzie pomóc.

Offline kolarz3

  • Użytkownik

# Grudzień 09, 2013, 01:41:07
Robię bota do takiej gry i potrzebna mi jest wiedza czy dany piksel zmiienił kolor. Jest to gra flash.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

  • +1
# Grudzień 09, 2013, 03:23:31
W takim razie najszybciej będzie chyba złapać od razu cały ekran.

Kodzik:
    static int scanlines[2000*2000];
    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);
   
    HDC hdcSource = GetDC(NULL);
    HDC hdcDest = CreateCompatibleDC(hdcSource);
    HBITMAP hbmOutput = CreateCompatibleBitmap(hdcSource,width,height);
   
    //Select bitmap into the compatible device context
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcDest,hbmOutput);

    //Block-transfer the image data from screen dc into output dc
    BitBlt(hdcDest,0,0,width,height,hdcSource,0,0,SRCCOPY);

    //Determine padding for use in allocating new memory
    int padding = 0;
    while ( (width * 3 + padding) % 4 != 0) padding++;
   
    //Create and fill BITMAPINFO structure to pass to GetDIBits
    BITMAPINFO bmi;
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = 0;
    bmi.bmiHeader.biSizeImage = height * (width * 3 + padding);
    bmi.bmiHeader.biXPelsPerMeter = 0;
    bmi.bmiHeader.biYPelsPerMeter = 0;
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;
     
    //Acquire bytes from bitmap
    GetDIBits(hdcDest,hbmOutput,0,height,scanlines,&bmi,DIB_RGB_COLORS);
   
    //Free output bitmap
    SelectObject(hdcDest,hbmOld);
    DeleteObject(hbmOutput);
   
    //Free DCs
    ReleaseDC(NULL,hdcSource);
    DeleteDC(hdcDest);

Offline kolarz3

  • Użytkownik

# Grudzień 11, 2013, 15:13:02
Mam coś takiego, działa chyba poprawnie, ale nie wiem czemu program po dłuższym czasie się zawiesza. Może za dużo pamieci bierze. Da się jeszcze to jakoś przyspieszyć?
#include <iostream>
#include <Windows.h>
#include <time.h>
#include <conio.h>
#include <list>
using namespace std;
void czekaj( float sekundy )
{
    clock_t koniec_czekania;
    koniec_czekania = clock() + sekundy * CLOCKS_PER_SEC;
    while( clock() < koniec_czekania ) { }
}
int main()
{

while(GetAsyncKeyState(0x31)==0)
{
}
czekaj(0.5);

int r3=0;
    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);
int padding = 0;
    while ( (width * 3 + padding) % 4 != 0) padding++;
BITMAPINFO bmi;
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = 0;
    bmi.bmiHeader.biSizeImage = height * (width * 3 + padding);
    bmi.bmiHeader.biXPelsPerMeter = 0;
    bmi.bmiHeader.biYPelsPerMeter = 0;
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;


COLORREF* pixel = new COLORREF [ width * height ];
while(GetAsyncKeyState(0x31)==0)
{
r3++;
    HDC hdcSource = GetDC(HWND_DESKTOP);
    HDC hdcDest = CreateCompatibleDC(hdcSource);
    HBITMAP hbmOutput = CreateCompatibleBitmap(hdcSource,width,height);
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcDest,hbmOutput);
    BitBlt(hdcDest,0,0,width,height,hdcSource,0,0,SRCCOPY);

    GetDIBits(hdcDest,hbmOutput,0,height,pixel,&bmi,DIB_RGB_COLORS);
int kolor=GetBValue(pixel[width*height/2]);
cout<<kolor<<endl;
}

cout<<r3;
system("PAUSE");

}

Offline Xion

  • Redaktor
    • xion.log

# Grudzień 11, 2013, 15:16:58
Tworzysz bitmapę w każdym przebiegu pętli wykonującej się tak szybko, jak to możliwe... What can be possibly go wrong? :)

Offline kolarz3

  • Użytkownik

# Grudzień 11, 2013, 15:31:19
A nooo. A teraz da się jeszcze jakoś przyspieszyć ?
#include <iostream>
#include <Windows.h>
#include <time.h>
#include <conio.h>
#include <list>
using namespace std;
void czekaj( float sekundy )
{
    clock_t koniec_czekania;
    koniec_czekania = clock() + sekundy * CLOCKS_PER_SEC;
    while( clock() < koniec_czekania ) { }
}
int main()
{

while(GetAsyncKeyState(0x31)==0)
{
}
czekaj(0.5);

int r3=0;
    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);
int padding = 0;
    while ( (width * 3 + padding) % 4 != 0) padding++;
BITMAPINFO bmi;
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = 0;
    bmi.bmiHeader.biSizeImage = height * (width * 3 + padding);
    bmi.bmiHeader.biXPelsPerMeter = 0;
    bmi.bmiHeader.biYPelsPerMeter = 0;
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;


COLORREF* pixel = new COLORREF [ width * height ];
HDC hdcSource ;
HDC hdcDest;
HBITMAP hbmOutput;
HBITMAP hbmOld;
while(GetAsyncKeyState(0x31)==0)
{
r3++;
    hdcSource = GetDC(HWND_DESKTOP);
    hdcDest = CreateCompatibleDC(hdcSource);
    hbmOutput = CreateCompatibleBitmap(hdcSource,width,height);
    hbmOld = (HBITMAP)SelectObject(hdcDest,hbmOutput);
    BitBlt(hdcDest,0,0,width,height,hdcSource,0,0,SRCCOPY);

    GetDIBits(hdcDest,hbmOutput,0,height,pixel,&bmi,DIB_RGB_COLORS);
int kolor=GetBValue(pixel[width*height/2]);
//cout<<kolor<<endl;
}

cout<<r3;
system("PAUSE");

}

Tylko że nie wiem czy dobrze wydobywam piksele. Bo wychodzi na to że źle?
kolor=GetBValue(pixel[p.y*width+p.x]);


// Edytuj posty zamiast pisać jeden pod drugim. -Xirdus
« Ostatnia zmiana: Grudzień 11, 2013, 18:34:30 wysłana przez Xirdus »

Offline Xirdus

  • Redaktor

# Grudzień 11, 2013, 18:33:14
1. Nadal tworzysz bitmapę w pętli. Zgadnij, co robi funkcja zaczynająca się od Create.
2. Funkcja GetBValue() wyciąga tylko składową niebieską. Cała wartość RGB siedzi już w tablicy pixel. Brotip: googluj sobie nazwę funkcji przed użyciem.
3. Aczkolwiek nie jest to błędem, to jak zależy ci na wydajności, to usuń tego BitBlt bo jest całkowicie niepotrzebny - wystarczy samo GetDIBits bezpośrednio z pulpitu.
4. Nigdzie nie kasujesz utworzonych zasobów. C++ to nie Java, swoje syfy trzeba sprzątać samemu.

Offline kolarz3

  • Użytkownik

# Grudzień 11, 2013, 18:44:39
Ok, wydajność teraz bardzo dobra. Ale czemu nie mogę się właściwie dostać do pikseli?

Offline Xion

  • Redaktor
    • xion.log

# Grudzień 11, 2013, 19:09:06
[OT]
Cytuj
4. Nigdzie nie kasujesz utworzonych zasobów. C++ to nie Java, swoje syfy trzeba sprzątać samemu.
Zasoby nie będące pamięcią trzeba sprzątać w C++, Javie i każdym innym języku ;p
[/OT]