Bild zuschneiden?



  • Hi.

    Ich habe eine Textkontur in einer Bitmap und möchte dieses nun passgenau zuschneiden.
    Dazu habe ich mir folgenden Algorithmus gebastelt:

    //Compiler: Borland C++ Builder 5
    
    void cut(Graphics::TBitmap *BmpToCut)
    {
     Graphics::TBitmap *bmp=new Graphics::TBitmap();
     bmp->Assign(BmpToCut);
    
     TRect source, dest;
    
     bool brk=false;
     for(int y1=0; y1<bmp->Height && !brk; y1++)
      for(int x1=0; x1<bmp->Width && !brk; x1++)
      {
       if(bmp->Canvas->Pixels[x1][y1]==kontur)
       {
        source.Top=y1;
        for(int x2=x1; x2>=0 && !brk; x2--)
         for(int y2=y1; y2<bmp->Height && !brk; y2++)
         {
          if(bmp->Canvas->Pixels[x2][y2]==kontur) break;
          if(y2==bmp->Height-1)
          {
           source.Left=x2+1;
           brk=true;
          }
         }
    
        brk=false;
        for(int x3=bmp->Width-1; x3>=0 && !brk; x3--)
         for(int y3=y1; y3<bmp->Height && !brk; y3++)
          if(bmp->Canvas->Pixels[x3][y3]==kontur)
          {
           source.Right=x3+1;
           brk=true;
          }
        }
       }
    
     brk=false;
     for(int y=bmp->Height-1; y>=0 && !brk; y--)
      for(int x=0; x<bmp->Width && !brk; x++)
       if(bmp->Canvas->Pixels[x][y]==kontur)
       { source.Bottom=y+1; brk=true; }
    
     dest.Top=0;
     dest.Left=0;
     dest.Bottom=source.Height();
     dest.Right=source.Width();
    
     BmpToCut->Width=0;
     BmpToCut->Height=0;
    
     BmpToCut->Width=dest.Right;
     BmpToCut->Height=dest.Bottom;
     BmpToCut->Canvas->CopyRect(dest, bmp->Canvas, source);
     BmpToCut->TransparentColor=background;
     delete bmp, &dest, &source;
     cut_b=true;
    }
    

    Dieser Algorithmus braucht bei großen Bitmaps natürlich extrem lange.
    Daher frage ich mich ob es da nichts schnelleres gibt.

    Danke für die Hilfe
    rean



  • Ich habe zwar deinen Algorithmus nur oberflächlich angeschaut, aber ich würde es so machen:

    Ausschnitt.x1 = 0;
    Ausschnitt.x2 = Bild.Breite - 1;
    Ausschnitt.y1 = 0;
    Ausschnitt.y2 = Bild.Hoehe - 1;
    
    for( int y = 0; y < Bild.Hoehe; y++ )
    {
        bool PixelGefunden = false;
        for( int x = Ausschnitt.x1; x < Ausschnitt.x2 + 1; x++ )
        {
            if( Bild.Pixel[x][y] != Hintergrundfarbe )
            {
                Ausschnitt.x1 = max( Ausschnitt.x1, x );
                Ausschnitt.x2 = min( Ausschnitt.x2, x );
                PixelGefunden = true;
            }
        }
    
        if( PixelGefunden )
        {
            Ausschnitt.y1 = max( Ausschnitt.y1, y );
            Ausschnitt.y2 = min( Ausschnitt.y2, y );
        }
    }
    
    for( int x = Ausschnitt.x1; x < Ausschnitt.x2 + 1; x++ )
    {
        for( int y = 0; y < Ausschnitt.y1; y++ )
        {
            if( Bild.Pixel[x][y] != Hintergrundfarbe )
            {
                Ausschnitt.y1 = y;
                break;
            }
        }
    
        for( int y = Bild.Hoehe - 1; y > Ausschnitt.y2; y-- )
        {
            if( Bild.Pixel[x][y] != Hintergrundfarbe )
            {
                Ausschnitt.y2 = y;
                break;
            }
        }
    }
    


  • In den Borland-Klassen gibts doch sicher auch die Möglichkeit Bildbereiche zu blitten per DeviceContext oder ähnlichem? Weil dann kannst dir die ganzen Schleifen sparen 🙂



  • Du solltest statt über die Eigenschaft Pixel, die jedesmal einen Aufruf von GetPixel() zur Folge hat, direkt auf die zugrundeliegenden Bilddaten mittels der ScanLine-Eigenschaft (liefert der nen Zeiger) zu greifen. Dann gehts schneller.

    Nix mit blitten nötig. Dort wird intern dann auch nur ne Schleife durchlaufen...



  • Sunday schrieb:

    Nix mit blitten nötig. Dort wird intern dann auch nur ne Schleife durchlaufen...

    Sicher?
    Das Blitten könnte durchaus effizienter über die Treiber umgesetzt sein, welche Windows dann nutzt.
    Und der Aufruf einer Funktion(nämlich das Blitten) sieht eh immer schöner aus, als wenn man selber Schleifen schreiben muss 🙂


Anmelden zum Antworten