[C++] Optymalizacja / alternatywy skryptu

0

Witam
Planuję zrobić coś w stylu "Ambilight" Philipsa do komputera. Całość sterowana portami RS232. Problem tkwi w prędkości działania algorytmu obliczającego przeważające kolory:

#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
    HDC Ekran = GetDC(GetDesktopWindow());
    COLORREF Kolor = RGB(255, 255, 255);
    int i,i2,i3;
    short int r,g,b;
    for (i=1; i!=2; i) {
        for (i2=1; i2<5; i2++) {
            for (i3=1;i3<3;i3++) {
                Kolor = GetPixel(Ekran, i2*200, i3*50);
                r+= GetRValue(Kolor);
                g+= GetGValue(Kolor);
                b+= GetBValue(Kolor);   
            }        
        }
        r=r/10;g=g/10;b=b/10;
        Sleep(100);
    }
    ReleaseDC(NULL, Ekran);
    return 0;
} 

To jest przykładowy algorytm obliczania średniego koloru z 10 punktów na górnej części ekranu. Program zżera 10% zasobów procesora 2x2.8GHz. Da się to jakoś zoptymalizować? A może jest jakieś całkowicie inne rozwiązanie?

0
  1. podejrzewam ze zmienna "i" specjalnie nie jest inkrementowana, aby miec infinite loop?
  2. short int r,g,b; sa nie zainicjalizowane. Ciesz się, że miałeś tam zera
  3. int i,i2,i3; w C++ mozna zmienne iteracyjne definiowac wewnatrz pierwszego czlonu FOR, w Twoim przypadku sądzę że wręcz należałoby
  4. zmienna Kolor spokojnie moze byc zdefiniowana jako tymczasowa, w linii z GetPixel
  5. zakladajac ze topmost ma byc faktycznie petla, przydaloby sie zerowac R/G/B przed zsumowaniem nowych wartosci. Po co Ci calka po czasie?
  6. sadze, że to co wyswietla Ci %nty, oszukuje Ciebie, jakos nie chce mi sie wierzyc, że 15x GetPixel jest az tak ciężkie. Nie ogladałem go od środka, nie wiem, może każde wywołanie robi kopie bitmapy desktopu? ale przeciez odebrales DC raz na poczatku.. Sprobuj - moze zamiast getpixelowac, zrzuc RAZ calosc REGIONU do bitmapy, potem bierz piksele z niej. A nuż bedize szybciej. ~>http://www.codeguru.com/forum/archive/index.php/t-271931.html ale przyznam ze nie czytalem ich kodu
  7. mozesz zerknac na http://www.asmcommunity.net/board/index.php?topic=17519.0 ktos tam sie chwali, ze przyspieszyl GetPixel znacznie

pkt 0-3) nie dotycza optymalizacji, tylko hm. bezpieczenstwa kodu. Wierz mi, to niczego nie spowolni ani nie przyspieszy, efekt po kompilacji bedzie ten sam jak masz teraz, a bedzie czysciej w kodzie.

0

W kodzie jest sporo pozostałości po wielu kombinacjach dlatego jest taki nieporządny. I faktycznie zapomniałem zerować kolorów w pętli :) A co do bitmap to nie próbowałem, ale szukając po forach zauważyłem, że to raczej nie przynosi efektu.
Znalazłem jeszcze funkcję CreateDIBSection, która ponoć działa szybciej.

Wpadłem na całkiem inny pomysł, ale tego już nie wiem jak napisać: program będzie robił zrzut ekranu, następnie górną część zmniejszy do rozmiaru 1x1. W efekcie powstanie piksel o średnim kolorze ze zmniejszonego obszaru. Byłbym wdzięczny, gdyby ktoś mógł mi podać jakiś kurs / nazwy funkcji do napisania czegoś takiego.

0

to co zaproponowales, to moj punkt numer 5), wiec przeczytaj go jeszcze raz.
patrzac zas doslownie na to co napisales, watpie zeby takie usrednianie bylo szybsze niz przeczytanie ze zrzutu 15 pikseli i reczne sumowanie.. stawiasz usrednianie kilkuset pikseli versus usrednianie 15 pikseli.. nie przeginaj z tym kobinowaniem.

0

GetPixel faktycznie za każdym wywołaniem robi sobie swoją własną kopię obrazu, potem pobiera dane z piksela i tymczasowy obraz usuwa - tak więc pobieranie pojedynczych pikseli zawsze będzie wolne. Mój pomysł opiera się na tym, że wyliczeniem kolorów tego piksela zajmie się algorytm zmniejszający, który (chyba) zadziała szyciej.

#include <Windows.h>
#include <CommDlg.h>
void PrintScreen ()
	{
	HDC hScreenDC;
	if ((hScreenDC = GetDC (NULL)) != NULL) {
		HDC hMemDC;

		if ((hMemDC = CreateCompatibleDC (hScreenDC)) != NULL) {
			HBITMAP hFullScreenBitmap;
			int iScreenWidth = GetSystemMetrics (SM_CXSCREEN);
			int iScreenHeight = GetSystemMetrics (SM_CYSCREEN);
			
			if ((hFullScreenBitmap = CreateCompatibleBitmap (hScreenDC, iScreenWidth, iScreenHeight)) != NULL) {
				HBITMAP hDefaultBitmap = (HBITMAP) SelectObject (hMemDC, hFullScreenBitmap);
				BitBlt (hMemDC, 0, 0, iScreenWidth, iScreenHeight, hScreenDC, 0, 0, SRCCOPY);
				SelectObject (hMemDC, hDefaultBitmap);
				SelectObject (hMemDC, hFullScreenBitmap);
/* Tutaj będą funkcje zmniejszające*/
				SelectObject (hMemDC, hDefaultBitmap);
				DeleteObject (hFullScreenBitmap);
				}
			DeleteDC (hMemDC);
			}
		ReleaseDC (NULL, hScreenDC);
		}
	}
int main() {
  PrintScreen ();     
}

Tu jest kod do zrzucania screenshota do pamięci. Mój problem polega na tym, że nie wiem jak mam wyciąć region i go zmniejszyć.

0
quetzalcoatl napisał(a)
  1. int i,i2,i3; w C++ mozna zmienne iteracyjne definiowac wewnatrz pierwszego czlonu FOR, w Twoim przypadku sądzę że wręcz należałoby

Możesz mi wyjaśnić na przykładzie?
Domyślam się, że chodzi o:

for (int e, t, i = 0;...
   for(t= 0; ...
      for (e = 0;...
...

?

0

Raczej:

for(int e = 0; e<666;e++){
  for(int g = 0;g<69;g++){
    for(int h = 123; h > 12; h--){
     }
  }
}

I tak dalej.

0
ticorman napisał(a)

GetPixel faktycznie za każdym wywołaniem robi sobie swoją własną kopię obrazu, potem pobiera dane z piksela i tymczasowy obraz usuwa - tak więc pobieranie pojedynczych pikseli zawsze będzie wolne. (..)
No i wszystko jasne.. W takim razie nie ma sie co zastanawiac, i na tychmiast przechodz na zrobienie 'screena' i czytanie pixeli z niego.

ticorman napisał(a)

Tu jest kod do zrzucania screenshota do pamięci. Mój problem polega na tym, że nie wiem jak mam wyciąć region i go zmniejszyć.
Uh oh. To moze zacznij od przeczytania parametrow CreateCompatibleBitmap oraz BitBlt. Zwlaszcza tej drugiej, parametry numer 4,5 i 7,8

0

Takie pytanie - nie lepiej zrobić bitmapę z bezpośrednim dostępem do bufora (bodaj CreateDIBSection) , skopiować (BitBlt) do niej konieczny fragment obrazu i bezpośrednio przez struktury/pointery czytać?

0

Stwierdziłem, że napisanie tego w C++ mnie przerasta, więc napisałem to w Visual Basic.
Tu jest kod, jeśli ktoś by potrzebował:

Dim rozdzielczosc As Rectangle = Screen.PrimaryScreen.Bounds
Dim pixelColor, kolorPiksela As Color
Dim piksel As New Bitmap(1, 1)
Dim screenshot As New Bitmap(rozdzielczosc.Width, rozdzielczosc.Height)
Dim graph As Graphics = Graphics.FromImage(screenshot)
Dim graph2 As Graphics = Graphics.FromImage(piksel)

Function pobierzPiksel(ByVal screenshot As Bitmap, ByVal x As Integer, ByVal y As Integer, ByVal x2 As Integer, ByVal y2 As Integer) As Color
    Dim obszar As New Rectangle(x, y, x2, y2)
    graph.CopyFromScreen(x, y, 0, 0, obszar.Size, CopyPixelOperation.SourceCopy)
    graph2.DrawImage(screenshot, 0, 0, 1, 1)
    pixelColor = piksel.GetPixel(0, 0)
    Return pixelColor
End Function

// q: to teraz to przepisz na C++ i sie zdziw, ze wyglada prawie tak samo..

1 użytkowników online, w tym zalogowanych: 0, gości: 1