Zugriff über Canvas->Pixels zu langsam - warum? alternativen Zugriff auf Pixel?



  • Hallo.

    Ich versuche in einem bitmap mit

    bmp->Canvas->Pixels[x,y]

    auf die einzelnen Pixel des Bildes zuzugreifen um sie dann einzeln zu manipulieren. (Schwellwertbildung -> Binärisierung)

    Das ganze dauert aber bei einem Bild mit etwas 600*500 Pixel fast 3 sec. Definitiv zu langsam. Woran kann das liegen? Gibt es eine andere Möglichkeit pixel direkt anzusteuern? ich der Hilfe habe ich nichts gefunden.

    Vielen Dank
    Jan



  • TBitmap::ScanLine ermöglicht den zeilenweisen Zugriff auf die Pixel. Ist um einiges schneller als über Canvas->Pixels[][].



  • so weit ich weiss aber nur zum lesen- oder?



  • Die Eigenschaft ScanLine ist readonly, aber über ScanLine kannst du schreibend auf die Pixel zugreifen (siehe Beispiel in der Hilfe).



  • ich habe das so eingebaut mit scanline.

    rot = GetRValue(ptr[x]);



  • hellsehen koennen wir noch nicht; zeig mal deinen gesamten code.

    der zugriff ueber Canvas->Pixels[x][y] ist deshalb so langsam, da Pixels ein Property von Canvas ist und ueber eine Get- & Set-Funktion beschrieben bzw. gelesen wird. damit hast du bei jedem pixel einen zusaetzlichen funktionsaufruf. dazu kommt noch der array-zugriff (2d-array). zuerst auf x und im anschluss auf y. durch die ganzen zusätzlichen funktionen sinkt natürlich die geschwindigkeit enorm und Pixels sollte daher nie verwendet werden sondern ScanLine.



  • so - jetzt habe ich die sache mit scanline am laufen. aber toll ist die geschwindigkeit immernoch nicht. was kann man das noch machen? bmp ist das Bitmap und die Bilder sind nicht sonderlich gross - das muss schneller gehen.

    void binaerisiere()
    {
        byte *ptr;
        for(int y=0; y<bmp->Height; y++)
        {
        	ptr = (byte *) bmp->ScanLine[y];
    
        	for (int x=0; x<bmp->Width; x++)
        	{
               	if (ptr[x] >= StrToInt(Form1->Schwellenwert_edit->Text))
                    ptr[x]= 230;
                else
                    ptr[x]= 0;
              }
        }
    }
    


  • Du könntest die Feldmatirx kopieren und über diesse die Manipulation dürchführen .
    Das beste währe aber sicherlich den Speicher ausfindigzumachen und dort die Manipulation vorzunehmen



  • was genau ist denn die Feldmatrix?

    wie würde ich denn Speicherbereich rankommen?



  • Wenn es um Performance geht haben Sachen wie StrToInt(Form1->Schwellenwert_edit->Text)) auf jeden Fall nichts in den Schleifen verloren, auch wenn das hier wohl nicht die Bremse ist.



  • ja - ist schon klar. ich hatte da zwischendurch auch schon feste werte drin - das hat keinen unterschied gemacht.



  • talshiar schrieb:

    void binaerisiere()
    {
        byte *ptr;
        for(int y=0; y<bmp->Height; y++)
        {
        	ptr = (byte *) bmp->ScanLine[y];
    
        	for (int x=0; x<bmp->Width; x++)
        	{
               	if (ptr[x] >= StrToInt(Form1->Schwellenwert_edit->Text))
                    ptr[x]= 230;
                else
                    ptr[x]= 0;
              }
        }
    }
    

    argh...

    1. weg mit StrToInt()
    -> bei jedem Pixel rufst du die Funktion auf (dort wird in ner Schleife
    eine String in ne Zahl konvertiert -> sehr schlecht, zumal die sich ja
    nicht aendert in der Schleife!)
    2. weg mit Form1->Schwellenwert_edit->Text
    -> bei jedem Pixel wird die Get-Funktion von Text aufgerufen
    -> sehr schlecht!
    3. weg mit bmp->Width und bmp->Height da hier bei jedem Pixel
    die Get-Funktion fuer Width und Height aufgerufen werden und sich
    die Hoehe und Breite ja kaum aendert!

    besser waere zum beispiel folgendes:

    typedef unsigned char u_char;
    typedef unsigned int  u_int;
    
    void binaerisiere()
    {
      u_char  Threshold = StrToInt(Form1->Schwellenwert_edit->Text);
      u_int   Height    = bmp->Height;
      u_int   Width     = bmp->Width;
      u_char *ptr;
      u_int   x, y;
    
      for (y = 0; y < Height; ++y)
      {
        ptr = (u_char*) bmp->ScanLine[y];
    
        for (x = 0; x < Width; ++x)
          *(ptr + x) = (*(ptr + x) >= Threshold ? 230 : 0);
      }
    }
    

    besser lebst du sowieso, wenn du dir ne eigene bild-klasse baust und den ganzen vcl schnickschnack weglaesst. damit bist du dann auch unabhaengiger von der entwicklungsumgebnung.

    ausserdem sollte die funktion das bild und den schwellwert uebergeben bekommen und diese nicht als globale variablen rumlungern!

    duerfte auf jeden schneller sein als deine version, wenn nicht solltest du deine compiler-optionen ueberpruefne (release-modus).


Anmelden zum Antworten